typescript 为什么keyof操作符会检索非枚举继承的?对象文字类型的属性?

hwamh0ep  于 2023-08-07  发布在  TypeScript
关注(0)|答案(1)|浏览(139)

请考虑以下TypeScript代码:

'use strict';

type Value = 1 | 2 ;
type Owner = 'ownerA' | 'ownerB';
type ItemType = 'itemTypeA' | 'itemTypeB';
type Item = {
  type: ItemType;
  owner: Owner;
  value: Value;
};

type AnotherType = {
  [k in keyof Item]: null | {
    [m in keyof Item[k]]: number;
  };
};

const v: AnotherType = {
  type: { itemTypeA: 0, itemTypeB: 1,},
  owner: { ownerA: 0, ownerB: 1,},
  value: null,
};

console.log(v);

字符串
在这种情况下,tsc抛出一个错误:
错误TS 2322:类型'{ itemTypeA:number; itemTypeB:number; }”不能分配给类型“{ [x:number]:number; toString:number; charAt:number; charCodeAt:编号; concat:number; indexOf:number; lastIndexOf:number; localeCompare:...
显然,由于某种原因,[m in keyof Item[k]]: number;迭代包含了不可枚举的,甚至是不存在的属性(不确定对象类型是否可以继承自Object.prototype的类型),比如:charCodeAt、charAt等
据我所知,这与'keyof'类型操作符的文档相矛盾,它被描述为:
keyof运算符接受一个对象类型,并生成其键的字符串或数字字面值联合。下面的类型P与类型P =“x”是同一类型|“y”:type Point = { x: number; y: number }; type P = keyof Point;
即,不存在“charAt”等。值,只有'x'和'y'。

可能与in运算符有关,但同样,在JS中,它只遍历对象的可枚举属性(不确定在TypeScript中,当它用作类型运算符时是否如此)。

有没有人能解释一下,这是怎么回事?

7ivaypg9

7ivaypg91#

你应该把你的类型改成类似

type AnotherType = {
    [K in keyof Item]: null | {
        [M in Item[K]]: number; // <-- no keyof
    };
};

字符串
在嵌套的mapped type中不使用keyof运算符。
M in keyof Item[K]的问题是Item[K]Item接口中的indexed access type,因此是ItemTypeOwnerValue中的一个,它们已经是您想要的类似键的文字类型的并集。由于Item[K]已经是keylike的,所以写keyof Item[K]是对keys-of-keys进行求值。想必你并不关心像"ownerA"这样的字符串的键(例如,"toUpperCase""length"等)或像1这样的数字的键(例如,"toFixed")。相反,您应该直接迭代Item[K]。毕竟,我们想要{[M in Owner]: number},nut {[M in keyof Owner]: number}
在我们做出这个改变之后,AnotherType等价于

type AnotherType = {
    type: {
        itemTypeA: number;
        itemTypeB: number;
    } | null;
    owner: {
        ownerA: number;
        ownerB: number;
    } | null;
    value: {
        1: number;
        2: number;
    } | null;
}


如所希望的那样。
Playground链接到代码

相关问题