typescript 支持 Conditional Types .
但是当我尝试设置 op
的值时作为字符串,它给了我错误,我如何检查类型和赋值?
export const t = <IsMulti extends boolean = false>(): void => {
const value = 'test';
type S = string;
type D = IsMulti extends true ? S[] : S;
const op: D = value;
console.log(op);
};
错误:Type 'string' is not assignable to type 'D'.
我什至尝试添加相同类型的参数 IsMulti
并基于它添加检查export const t = <IsMulti extends boolean = false>(isMulti: IsMulti): void => {
const value = 'test';
type S = string;
type D = IsMulti extends true ? S[] : S;
if (!isMulti) {
const op: D = value;
console.log(op);
}
};
它仍然给出同样的错误。最佳答案
评价conditional types这取决于尚未指定的 generic类型参数通常由编译器延迟;如果编译器不确切知道 IsMulti
是,那么它不知道到底是什么IsMulti extends true ? S[] : S
是,所以它不会让你分配一个类型的值(比如)S
到那个条件类型,因为它无法验证这是一个类型安全的操作。编译器甚至没有真正尝试评估这种条件类型。它使它们成为不透明的东西,几乎没有任何东西可以分配给它。
对于您的第一个示例,这是编译器所需的行为;分配 string
确实不安全至op
因为D
很可能是string[]
.没有什么能阻止某人调用 t<true>()
.只是因为IsMulti
有一个 default的 false
不代表是false
.
对于您的第二个示例,这是当前 TypeScript 的限制。编译器不能使用 control flow analysis缩小类型参数。因此它无法验证可分配性参见 microsoft/TypeScript#33912详情。
当您查看 if (!isMulti)
,编译器缩小 isMulti
的类型在 IsMulti
的后续代码块内只需输入 false
:
export const t = <IsMulti extends boolean = false>(isMulti: IsMulti): void => {
if (!isMulti) {
// isMulti is now known to be false
const fls: false = isMulti; // okay
const tru: true = isMulti; // error
}
};
但它并没有缩小类型参数IsMulti
本身。通常这也是编译器期望的行为,因为 IsMulti extends boolean
表示 IsMulti
实际上可能是完整的union boolean
(而不是只是 true
或只是 false
),所以检查类型的值 IsMulti
对缩小 IsMulti
没有用处本身。所有你能说的 if (!isMulti)
是IsMulti
不能只是true
...但它可能仍然是 boolean
.当然如果是boolean
,然后 D
, 一个 distributive conditional type将成为联合 S[] | S
,并且您应该被允许分配 string
到那个。所以没有合理的方法来分配 "test"
至op
应该是不安全的。然而,编译器无法验证这一点。它固执地离开
IsMulti
一个人,不会让你分配任何东西给D
因为它推迟了评估。如果有一些支持的方法来缩小类型参数,或者验证泛型条件类型的可分配性,那就太好了。目前,真的没有。上面链接的 GitHub 问题是一个改进此问题的功能请求,并且有许多相关请求可能会有所帮助(例如,microsoft/TypeScript#27808 可以将 IsMulti
限制为完全 true
或完全 false
,大概然后if (!isMulti)
会将以前的通用类型 IsMulti
缩小到特定类型 false
,并且 D
将被急切地评估)。您可以解决这些问题并给他们一个 👍,但短期内这里会发生任何事情并不明显。相反,在这种你比编译器更了解类型的情况下,你可以使用 type assertion抑制可分配性错误:
export const t = <IsMulti extends boolean = false>(isMulti: IsMulti): void => {
const value = 'test';
type S = string;
type D = IsMulti extends true ? S[] : S;
if (!isMulti) {
const op = value as D; // okay
console.log(op);
}
};
通过写 value as D
你告诉编译器你知道 value
绝对是 D
类型,即使编译器不能。这允许程序无错误地编译。请注意,这不是魔术,并且通过执行类型断言,您可以从编译器中承担一些类型安全的责任。如果你犯了一个错误或对编译器撒谎,它不能总是捕获它:if (!isMulti) {
const op = ["oopsie"] as D; // still okay
console.log(op);
}
所以要小心!Playground link to code
关于javascript - typescript:从条件类型派生类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71018294/