我有以下(简化的)代码:
type GetInput<U> = {
defaultValue?: U
}
const getBool = (input: GetInput<boolean>) => {
return input.defaultValue ?? true
}
const getNumber = (input: GetInput<number>) => {
return input.defaultValue ?? 3;
}
type GetFunc<U> = (input: GetInput<U>) => U;
type ToType<T extends 'boolean' | 'number'> =
T extends 'boolean'
? boolean
: T extends 'number'
? number
: never;
type GlobalGetInput<
T extends 'boolean' | 'number',
U extends ToType<T>
> = {
type: T;
defaultValue?: U;
};
const get = <T extends 'boolean' | 'number', U extends ToType<T>>(input: GlobalGetInput<T, U>) => {
let func: GetFunc<U>;
switch (input.type) {
case 'boolean':
func = getBool;
break;
case 'number':
func = getNumber;
break;
default:
throw new Error('Invalid type')
}
return func({ defaultValue: input.defaultValue })
}
get({ type: 'boolean', defaultValue: true })
运行正常,但在 func = getBool;
中打字失败
Type '(input: GetInput<boolean>) => boolean' is not assignable to type 'GetFunc<U>'.
Types of parameters 'input' and 'input' are incompatible.
Type 'GetInput<U>' is not assignable to type 'GetInput<boolean>'.
Type 'U' is not assignable to type 'boolean'.
Type 'ToType<T>' is not assignable to type 'boolean'.
Type 'boolean | (T extends "number" ? number : never)' is not assignable to type 'boolean'.
Type 'T extends "number" ? number : never' is not assignable to type 'boolean'.
Type 'number' is not assignable to type 'boolean'.
Type 'number' is not assignable to type 'boolean'.
Type 'number | boolean' is not assignable to type 'boolean'.
Type 'number' is not assignable to type 'boolean'.
发生这种情况是因为我不知道如何告诉编译器,如果在类型参数中传递了字符串 boolean
,U 只能是 boolean
类型。如果它是对象的联合,我们可以使用静态属性进行区分,但对于标量的联合,我不知道。
谢谢!
答案 0 :(得分:1)
发生这种情况是因为差异。 TypeScript 可以防止你犯错。看下面的例子:
@Override
@EntityGraph(attributePaths = { "sentMessages", "receivedMessages" })
Optional<Profile> findById(int id);
在最后一个示例中,因为您将 // you can't assign a function with a broader result to a narrower one
declare let fnA: () => 1 | 2
declare let fnB: () => 1
fnB = fnA
// you can't assign a function with narrower params to a broader one
declare let fnC: (a: 1 | 2) => 3
declare let fnD: (a: 1) => 3
fnC = fnD
分配给 fnD
,所以您的意思是 fnC
可以处理与 fnD
相同的输入 - 但事实并非如此。这可能会导致运行时错误。
当您看到此类错误消息时,请记住 TypeScript 只是警告您您没有遵守其差异规则。如果您想了解更多有关此内容的信息,有关于它和其他 presentation 的优秀post。
在您的情况下,TypeScript 无法看到您正在正确处理事情,并且仍然认为您的操作不安全。因为您知道自己在做什么,所以您需要告诉 TypeScript 这很好。小心点。
fnC
我通常使用 const get = <T extends 'boolean' | 'number', U extends ToType<T>>(input: GlobalGetInput<T, U>) => {
let func: GetFunc<U>;
switch (input.type) {
case 'boolean':
func = getBool as any as GetFunc<U>;
break;
case 'number':
func = getNumber as any as GetFunc<U>;
break;
default:
throw new Error('Invalid type')
}
return func({ defaultValue: input.defaultValue })
}
来强烈表示这是一个覆盖,但您也可以any
,这取决于您。