俗話說 OOP 學得好,Coding 沒煩惱。然後 Swift 有 POP,Ruby 有 mixin,還暫且不說 FP ㄏ
From the ancent......the Dragon 🐲......
讓我們從講古開始切入,其實 TypeScript 已經從古早時候就一直存在 (好吧說長不長說短不短的 5 年),只是近期內開始受到歡迎,吸引更多的開發者選擇使用 TypeScript,並且有穩定的商業應用表現 (有興趣的各位可以聽聽看 SoftwareEnginneringDaily 訪問 slack 使用 TypeScript 的經驗分享 - 傳送門)。
Compare with Flow!?
Facebook 毋庸置疑的贏了一場漂亮的戰爭,不管是 React 也好 babel 也行,
interface IntlExtension {
intl: InjectedIntl
}
function mountWithIntl<C extends IntlExtension>(node: React.ReactElement<C>) {
const intlProvider = new IntlProvider({ locale: 'zh-TW', messages }, {})
const { intl } = intlProvider.getChildContext()
return mount(
React.cloneElement(node, { intl }) as React.ReactElement<C>,
{
context: { intl },
childContextTypes: { intl: intlShape }
}
)
}
https://softwareengineeringdaily.com/?s=typescript
export interface TableProps<Data extends BasicDataDefine> {
classNamePrefix?: string
wrapperClassName?: string
className?: string
loading?: boolean
loader?: JSX.Element
rowSelection?: RowSelectionOption<Data>
pagination?: PaginationOption
dataSource: Data[]
columns: BasicColumnDefine[]
children?: undefined
// #TODO: filter or sorting function
onChange?: (currentPage: number, pageSize: number) => void
}
interface DefaultProps {
classNamePrefix: string
wrapperClassName: string
className: string
loading: boolean
loader: JSX.Element
}
type PropsWithDefault = TableProps & DefaultProps
TS2315: Type 'PropsWithDefault' is not generic.
deconstructor
this.selectedRecords = dataSource.filter(data =>
(data.key ? false : selectedKeys.includes(data.key))
)
TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
Type 'undefined' is not assignable to type 'string'.
this.selectedRecords = dataSource.filter(data =>
(data.key ? false : selectedKeys.includes(data.key as string))
)
const foo?: string = undefined
console.log(foo as string)
Overload!?
我們期望的 Overload in Swift
class User {
func register(name: String, gender: Gender, age: Int) {
...
}
func register(facebookID: String, gender: Gender) {
...
}
func register(referURL: URL) {
...
}
}
Protocol 版本
protocol User {
func register(name: String, gender: Gender, age: Int)
func register(facebookID: String, gender: Gender)
func register(referURL: URL)
}
哦哦哦!? TypeScript 有型態,所以把前面的邏輯慣例應該可以套用在 TypeScript 吧?
class User {
register(name: string, gender: Gender, age: number): void {
...
}
register(facebookID: string, gender: Gender): void {
...
}
register(referURL: URL): void {
...
}
}
......淦,怎麼只有最後一個 method 被叫到!!看了一下官方的文件...好吧,手動處理囉!
class User {
register(name: string, gender: Gender, age: number): void;
register(facebookID: string, gender: Gender): void;
register(referURL: URL): void;
register(nameOrFacebookIDOrReferURL: URL | string, gender?: Gender, age?: number): void {
......
}
}
雖然這樣寫真心非常醜,不過至少可以算是一種往前踏了一個閃身的改進了吧(?)
嗯,那這樣訂個 interface 如果要有 overload 大概也知道要怎麼做了。
interface User {
register(name: string, gender: Gender, age: number): void;
register(facebookID: string, gender: Gender): void;
register(referURL: URL): void;
register(nameOrFacebookIDOrReferURL: URL | string, gender?: Gender, age?: number): void;
}
WTF!? 怎麼有 4 個 method,做 Overload 處理的只有三個啊?最後一個實作細節怎麼被暴露出來了...
其實在 interface 宣告層想要有 Overload 效果的話,只要宣告需要的 method,而實際上會被呼叫到的 method 在 implement interface 的時候寫上就沒問題了。
interface User {
register(name: string, gender: Gender, age: number);
register(facebookID: string, gender: Gender);
register(referURL: URL);
}
const user: User {
...
register(nameOrFacebookIDOrReferURL: URL | string, gender?: Gender, age?: number) {
......
}
}
// Or
class Member implements User {
...
register(nameOrFacebookIDOrReferURL: URL | string, gender?: Gender, age?: number) {
......
}
}