我写了code:
var x: { length: 3 } = "abc";
并且无法通过消息编译
类型'“ abc”'不能分配给类型'{length:3; }'。
但是字符串abc
的长度肯定等于3。怎么了?
"abc"
是string
,而{ length: 3 }
是具有length
属性的对象,该属性必须等于数字3,它们根本不相交。
但是this code是有效的:
var y: { length: number } = "abc";
所以似乎对象没有问题?
答案 0 :(得分:3)
与length
相比,TypeScript目前对string literal types的number
属性一无所知。对于字符串文字的任何字符的类型,也将不会是string
的事实更加具体。在运行时,"abc".length
将是3
,但是编译器只知道它是number
。在运行时,"abc"[1]
将是"b"
,但是编译器只知道它是string
。
有一个open issue, microsoft/TypeScript#34692,,它表明字符串文字会自动缩小。如果您希望看到这种情况发生,则可能想去那里给它一个?或描述用例,如果您认为它特别令人信服。
如果出于某种原因,您需要为特定的字符串文字输入更具体的类型,则可以使用type assertion来将所需的期望值手动通知编译器,例如:
const x = "abc" as StringLiteral<"abc", ["a", "b", "c"]>;
const len = x.length; // const len: 3
console.log(len); // 3
const b = x.charAt(1).charAt(0)[0][0] // const b: StringLiteral<"b",["b"]>
console.log(b); // "b"
我的StringLiteral
类型的定义如下
type StrToNum = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
type Rev<T extends Record<keyof T, keyof any>> = {
[K in T[keyof T]]: { [P in keyof T]: T[P] extends K ? P : never }[keyof T]
};
type NumToStr = Rev<Pick<StrToNum, Exclude<keyof StrToNum, keyof any[]>>>;
type StringLiteral<T extends string, A extends string[] = [T]> =
{ [K in "length" | Exclude<keyof A, keyof any[]>]:
A[K] extends string ? StringLiteral<A[K], [A[K]]> : A[K] } & {
charAt<N extends keyof NumToStr>(
pos: N
): StringLiteral<Extract<A[Extract<NumToStr[N], keyof A>], string>>
} & T;
但是我无法想象值得付出努力。
好的,希望能有所帮助;祝你好运!