动态创建输出对象的typescript类型



我试图为我的对象Record<string, string | number, {} | []>创建typescripttype,如下-


const input = {
"test": 1,
"test2": "2",
}
const output = {
test: {
"testData": 1,
"testIsError": false,
},
test2: {
"test2Data": "2",
"test2IsError": false,
}
}

我希望输出键的类型为object,其中${key}Data与输入对象中的键的类型相同。

我知道这可以更好地优化到下面的输出对象,这是干净的&可读如下-

type Value<T> = {
data: T;
isError: boolean;
}
type BetterType<T> = {
[K in keyof T]: Value<T[K]>;
}
const test = {
"test": 1,
"test2": "2",
}
const test2: BetterType<typeof test> = {
test: {
data: 1,
isError: false,
},
test2: {
data: "will infer as string",
isError: false,
}
}

但是,出于好奇,我想知道我的上述原始问题是否可以在打字稿中解决。

我倾向于把你的字体定义为:

type InToOut<T extends object> = { [K in keyof T]:
{ [P in "Data" | "IsError" as `${Exclude<K, symbol>}${P}`]:
P extends "Data" ? T[K] : boolean
}
};

会导致我认为你正在寻找的转换:

const input = {
"test": 1,
"test2": "2",
}

type Out = InToOut<typeof input>;
/* type Out = {
test: {
testData: number;
testIsError: boolean;
};
test2: {
test2Data: string;
test2IsError: boolean;
};
} */

工作原理:

type InToOut<T extends object> = { [K in keyof T]:
{ [P in "Data" | "IsError" as `${Exclude<K, symbol>}${P}`]:
P extends "Data" ? T[K] : boolean
}
};

这是一个映射类型,即输入类型T中每个具有K键的属性都转换为具有相同键的输出属性类型。输出属性类型为

{ [P in "Data" | "IsError" as `${Exclude<K, symbol>}${P}`]:
P extends "Data" ? T[K] : boolean
}

是另一个映射类型;它迭代字符串字面值类型"Data""IsError",并使用键重映射为其中的每个字面值输出一个带有转换后的的属性。转换后的键是`${Exclude<K, symbol>}${P}`,它是一个模板字面值类型,表示原始对象中的键K"Data""IsError"中的键P的连接。从概念上讲,模板文字类型将是`${K}${P}`,但由于K可能是symbol,并且由于symbol不能通过模板文字正确序列化,我们需要从考虑中排除symbol。因此使用Exclude实用程序类型和Exclude<K, symbol>.

所以关键是K-加上-"Data"-或K-加上-"IsError"。这个值是一个条件类型P extends "Data" ? T[K] : boolean,所以如果"Data"已经被添加,那么属性就是T[K],对应于原始T对象类型中键K的属性的索引访问类型;如果添加了"IsError",则属性为boolean


顺便说一下,您不必使用键重映射和条件类型来获得等效类型,但我喜欢输出类型的方式。一个等价的解是:

type InToOut<T extends object> =
{ [K in Exclude<keyof T, symbol>]:
{ [P in `${K}Data`]: T[K] } &
{ [P in `${K}IsError`]: boolean }
};
type Out = InToOut<typeof input>;
/* type Out = {
test: {
testData: number;
} & {
testIsError: boolean;
};
test2: {
test2Data: string;
} & {
test2IsError: boolean;
};
} */

使用交集将K+"Data"K+"IsError"属性连接成一个对象。

Playground链接到代码

相关内容

  • 没有找到相关文章

最新更新