TypescriptMap类型问题

rsl1atfo  于 2023-06-30  发布在  TypeScript
关注(0)|答案(1)|浏览(116)

我试图从嵌套对象中获取Map类型。我需要得到一个点链接的对象的键。如果对象看起来像这样:

{a: {b: 'c'}, d: 'asdf'}

我应该从类型中得到'a.b' | 'd'。我这么做了,而且很有效:

type ITranslationKeys<T> = {
  [key in keyof T]: key extends string ? (T[key] extends string ? key : `${key}.${ITranslationKeys<T[key]>}`) : never;
}[keyof T];

const value = {a: {b: 'c'}, d: 'asdf'} as const;
    
type TValue = ITranslationKeys<typeof value>;

但是正如你所看到的,我必须检查else子句中的key extends string或${key}是否会失败,因为symbol不能分配给string。没有key extends string ? ... : never部分,还有其他方法可以做到这一点吗?
我也试过扩展T:T extends Record<string,any>但没有工作。
错误:

TS2322: Type 'key' is not assignable to type 'string | number | bigint | boolean | null | undefined'.
  Type 'keyof T' is not assignable to type 'string | number | bigint | boolean | null | undefined'.
    Type 'string | number | symbol' is not assignable to type 'string | number | bigint | boolean | null | undefined'.
      Type 'symbol' is not assignable to type 'string | number | bigint | boolean | null | undefined'.

Typescript 4,但如果它只可能在TS5只是让我知道。

3pvhb19x

3pvhb19x1#

让我们从一些基本的交集开始。与基元类型的交集是它们的数学交集,这意味着结果是两个集合(类型)中的元素。
number和union没有任何共同之处:

// never
type Case1 = ('a' | 'b' | 'c') & number

string是任何字符串的超类型,也就是任何字符串,字符串的并集是string的子集,交集将是并集本身,因为string包括任何字符串:

// 'a' | 'b' | 'c'
type Case2= ('a' | 'b' | 'c') & string;

现在,让我们让联合包含一些数字沿着字符串:

// 3
type Case3 = ('a' | 'b' | 3) & number
// 'a' | 'b'
type Case4 = ('a' | 'b' | 3) & string

我们可以得出结论,通过使用交集,我们可以检索所需的值:

type A = {
  1: 'a';
  b: 'b';
};
// 'b'
type Case2 = keyof A & string;

让我们修改Map的类型:

type ITranslationKeys<T> = { // no error
    [K in keyof T & string]: 
    T[K] extends string
    ? K
    : `${K}.${ITranslationKeys<T[K]>}`
}[keyof T & string];

或者,我们可以使用Extract内置的实用程序类型,它只返回扩展第二个参数的第一个参数的成员:

type ITranslationKeys<T> = {
  [K in Extract<keyof T, string>]: T[K] extends string
    ? K
    : `${K}.${ITranslationKeys<T[K]>}`;
}[Extract<keyof T, string>];

相关问题