我有一个这样的界面
interface Test {
values: string[] | number[] | Date[]
// more properties
}
我想创建另一个使类型特定的接口。我正在尝试的是:
interface TestWithType<T extends string | number | Date> extends Test {
values: T[];
}
但这失败并显示错误Type 'string' is not assignable to type 'Date'
。
什么是正确的语法?如果属性values
不是数组,这将正常工作
interface Test {
values: string | number | Date
}
interface TestWithType<T extends string | number | Date> extends Test {
values: T;
}
正如您所注意到的,您不能通过string[] | number[] | Date[]
apply 制作类型为 的元素数组来获得string | number | Date
。由于(string | number | Date)[]
比 更宽string[] | number[] | Date[]
,您会收到编译器错误,因为您无法扩大子类型的属性。
@MattMcCutchen 的回答提供了一些解决方法。这是另一种方式:
如果您有一个类似的联合string | number | Date
并希望以编程方式将其转换为类似数组的联合string[] | number[] | Date[]
,则可以使用分布条件类型:
type DistributeArray<T> = T extends any ? T[] : never;
然后你可以定义TestWithType
为DistributeArray
:
// no error:
interface TestWithType<T extends string | number | Date> extends Test {
values: DistributeArray<T>;
}
并验证它的行为是否符合您的预期:
declare const testWithString: TestWithType<string>
testWithString.values; // string[]
declare const testWithDate: TestWithType<Date>
testWithDate.values; // Date[]
declare const testWithStringOrNumber: TestWithType<string | number>
testWithStringOrNumber.values; // string[] | number[]
希望有帮助。祝你好运!
编辑:
作为一个相关的问题,有没有办法禁止将联合类型传递给泛型?(如要求最多只指定字符串、数字或日期之一)
是的,这是可能的,但它需要以一种让我不舒服的方式滥用类型系统。如果您不需要,我建议您不要这样做。这里是:
type DistributeArray<T> = T extends any ? T[] : never;
type NotAUnion<T> = [T] extends [infer U] ? U extends any ?
T extends U ? unknown : never : never : never
type ErrorMsg = "NO UNIONS ALLOWED, PAL"
interface TestWithType<T extends (
unknown extends NotAUnion<T> ? string | number | Date : ErrorMsg
)> extends Test {
values: DistributeArray<T>
}
declare const testWithString: TestWithType<string> // okay
declare const testWithDate: TestWithType<Date> // okay
declare const testWithStringOrNumber: TestWithType<string | number> // error:
// 'string | number' does not satisfy the constraint '"NO UNIONS ALLOWED, PAL"'.
如果不是联合,则该类型NotAUnion<T>
评估为unknown
(顶部类型)T
...否则评估为never
(底部类型)。然后,在TestWithType
类型T
被限制为 时unknown extends NotAUnion<T> ? string | number | Date : ErrorMsg
,几乎没有绕过针对循环引用的规则。如果你通过一个非联合作为T
,它会变得T extends string | number | Date
和以前一样。如果你传递一个联合,它就会变成T extends ErrorMsg
, 一个字符串文字类型。由于联合永远不会扩展字符串文字,它会失败......并且您得到的错误消息将涉及ErrorMsg
,因此它应该足以让开发人员意识到发生了什么。它有效,但它是非常非常粗略的东西。不过是你要求的。
再次祝你好运!
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句