function 有分 declare 跟 invoke 對吧
type 也有
對 term level 來講 type 不管是 declare 還是 invoke ,都是宣告
我大概理解這個問題了。我會有這樣錯誤的觀念,是我之前在寫 ts 版本的 redux saga的時候,遇到這個問題。
當時我的解決方式,是將 takeLatest
加上 any, error訊息就消失了。
function * loginHandler({ payload }: { payload: LoginRequest }) {
// do something ....
}
export default function * () {
yield takeLatest<any>(LOGIN, loginHandler);
}
如果takeLatest不加 any的話,會報 issues上的error:
Argument of type '"LOGIN"' is not assignable to parameter of type 'TakeableChannel<unknown>'.
當時一直認為是因為 takeLatest 有標 generic type。所以在使用時一定要給它一個型態。
你跟我提到 type variable的概念以後,我覺得一定有地方有問題,所以再試著去理解一次。
我認為這裡的問題應該是,因為我在 loginHandler
function 時,使用解構賦值,直接從 Action
object 中取出 payload
,
並只標出 payload 的型態。
而在 redux saga 的實作中,會找 action 中的 type 屬性,並將它的型態賦與TakeableChannel<T>
的 T:
// 一個 action。
interface Action {
type: string; // <- 這一個type 會是 TakeableChannel<T> 的 <T>
payload: any;
}
// .... (some code)
// 這裡只取出 payload,因此 takeableChannel取 type 的 型態的時候,會是 `unknown`
function * loginHandler({ payload }: { payload: LoginRequest }) {
// do something
}
這裡還有一個我沒有注意到的特性,就是takeLatest
的 type variable 可以是 literal string。
這是不是代表typescript中的 type variable 可以是一個抽象的型態?
// LOGIN 是我定義的 const string。
// takeLatest(LOGIN, loginHandler) 的 type hint:
// takeLatest<"LOGIN">(pattern: "LOGIN", worker: (action: Action<any>) => any): ForkEffect<never>
所以其實真正的問題並不是 takeLatest一定要加上 generic type。
而是因為在lib function 堆疊的過程中,lost 掉了某個 generic type,所以才會報錯。
照著 issue 上的回覆改一下 code,就不會報錯了。
function * loginHandler({ type, payload }: { type: typeof LOGIN, payload: LoginRequest }) {
// ..........
}
// ....
export default function * () {
yield takeLatest(LOGIN, loginHandler);
}
這又是一個我自以為我懂了的經典案例……
弄懂了這個關係以後,我更理解了 type variable ( generic type)的觀念;
修正觀念後,對我標 type signature應該是有幫助的。
還有你不斷提到的 generic type
跟 haskell 的 type variable
其實只有語法上的不同,這樣應該也算真的理解了。
https://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal-types