gpt4 book ai didi

typescript - typescript 中的条件类型

转载 作者:行者123 更新时间:2023-12-04 07:42:11 25 4
gpt4 key购买 nike

假设我有一个想要传递参数的函数。我自己的条件类型是基于参数的类型,但是当我想根据接口(interface)返回值时,函数给我一个错误。
这是实际的代码:

interface IdLabel {
id: number;
}

interface NameLabel {
name: string;
}

type NameOrId<T extends string | number> = T extends number ? IdLabel : NameLabel;

function createLabel<T extends string | number>(idOrName: T): NameOrId<T> {
if (typeof idOrName === "number") {
return {
id: idOrName
};
} else {
return {
name: idOrName
};
}
}

const a = createLabel(1);
const b = createLabel("something");
您可以在这张图片中看到错误:
enter image description here
这是文本错误:
Type '{ id: T & number; }' is not assignable to type 'NameOrId<T>'.
Type '{ name: T; }' is not assignable to type 'NameOrId<T>'.

最佳答案

当条件类型如 NameOrId<T>取决于未解析的类型参数,如 T createLabel()的体内,编译器推迟评估它。这种类型对编译器来说本质​​上是不透明的,因此它通常无法验证像 {id: idOrName} 这样的特定值。可以分配给它。
当您查看 typeof idOrName , control flow analysis将缩小 idOrName 的表观类型, 但这不会缩小类型参数 T本身。如果 typeof idOrName === "string" , idOrName现在被称为 string 类型(或 T & string ),但 T仍然可能是 string | number ,并且仍然是一个未解析的泛型类型参数。
这是 TypeScript 的一个已知痛点。有一个 Unresolved 问题,microsoft/TypeScript#33912 ,要求某种方式允许控制流分析来验证对未解析的条件类型的可分配性,尤其是作为您想要的函数的返回值。除非该问题得到解决,否则您将不得不解决它。

解决方法:
每当您遇到确定表达式 expr 的情况时是 Type 类型但编译器不是,你总是可以使用 type assertion告诉编译器:expr as Type ,或者,在编译器看到类型 expr 的情况下与 Type 完全无关,您可能必须写 expr as any as Type或使用其他一些中间断言。
那会给你这个:

function createLabelAssert<T extends string | number>(idOrName: T): NameOrId<T> {
if (typeof idOrName === "number") {
return {
id: idOrName
} as unknown as NameOrId<T>;
} else {
return {
name: idOrName
} as unknown as NameOrId<T>;
}
}
这解决了错误。请注意,通过做出断言,您将对类型安全负责。如果您修改了 typeof idOrName === "number"查看 typeof idOrName !== "number" ,仍然没有编译器错误。但是你会在运行时不开心。

当您有一个函数的返回类型无法在实现中验证时,您可以执行类型断言的“道德等价”: overload具有单个调用签名。重载实现的检查比常规函数更宽松,因此您可以获得与类型断言相同的行为,而不必在每个 return 处进行断言。分别行:
// call signature
function createLabel<T extends string | number>(idOrName: T): NameOrId<T>;
// implementation
function createLabel(idOrName: string | number): NameOrId<string | number> {
if (typeof idOrName === "number") {
return {
id: idOrName
};
} else {
return {
name: idOrName
};
}
}
调用签名相同,但现在实现签名只是来自 string | number 的映射。至 IdLabel | NameLabel .同样,编译器不会发现您检查 typeof idOrName !== "number" 的问题。不小心,所以你在这里也需要小心。
Playground link to code

关于typescript - typescript 中的条件类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67403300/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com