如何根据下面的代码推断
R
的返回类型。
export type SequenceDefinition<S extends string> = {
keys: S[] | Readonly<S[]>,
actions: Record<S, <R>(data: SequenceData<S, SequenceDefinition<S>>) => R>
}
type SequenceData<S extends string, T extends SequenceDefinition<any>> = {
get: (key: S) => ReturnType<T['actions'][S]>
}
export type SequenceCreatorFn = <S extends string>(config: SequenceDefinition<S>) => void;
export const sequence: SequenceCreatorFn = (config) => {
console.log(config);
};
const result = sequence({
keys: ['load', 'save', 'log'],
actions: {
load: () => {. // <- Error here
return { a: 1, b: 2 };
},
save: (data) => { // <- Error here
data.get('load');
return true;
},
log: () => { // <- Error here
return 1;
}
}
});
错误信息是:
Type '() => { a: number; b: number; }' is not assignable to type '<R>(data: SequenceData<"load" | "save" | "log", SequenceDefinition<"load" | "save" | "log">>) => R'.
Type '{ a: number; b: number; }' is not assignable to type 'R'.
'R' could be instantiated with an arbitrary type which could be unrelated to '{ a: number; b: number; }'.
any
或 unknown
作为返回类型。data.get
有一个强类型定义。Typescript 无法推断 R 的类型,因为它可以是任何类型。如果你以这个功能为例
function test(
// This is the type of your sequence config
config: SequenceDefinition<"load" | "save" | "log">
){
config.actions.load()
}
你可以看到,仅通过输入类型的定义,打字稿无法知道 load 返回什么,相反,任何具有 load、save 和 log 3 个函数的函数都可以分配给
SequenceDefinition<"load" | "save" | "log">
。
解决方案是让您的类型更具辨别力,以便对于每个操作,该函数只能返回单一类型
export type SequenceDefinition<Actions extends Record<string,unknown>> = {
keys: (keyof Actions)[],
actions:{
[key in keyof Actions]: (data: SequenceData<Actions>) => Actions[key]
}
}
type SequenceData<Actions extends Record<string,unknown>> = {
get: <Key extends keyof Actions>(key: Key) => Actions[Key]
}
export type SequenceCreatorFn = <Actions extends Record<string,unknown>>(config: SequenceDefinition<Actions>) => void;
export const sequence: SequenceCreatorFn = (config) => {
console.log(config);
};
const result = sequence({
keys: ['load', 'save', 'log'],
actions: {
load: () => {
return { a: 1, b: 2 };
},
save: (data) => {
data.get('load');
return true;
},
log: () => {
return 1;
}
}
});
在这种情况下
SequenceDefinition
不再仅由键定义,还由函数返回的值定义