如何创建一个可以接受任何基本类型或基本类型组合的类型



我想创建一个只接受"simple"数据(用例:日志元数据)。它的定义是递归的。我愿意接受:

  • 原始类型
  • 任何以字符串键和此类型作为值的对象
  • 此类型的任何数组

到目前为止,我这样做了:

type Primitive = string | number | boolean | null
type LogMetadata = {
readonly [key: string]: Primitive | LogMetadata | Array<LogMetadata>
}
function log(message:string, LogMetadata) {
// implementation irrelevant to the question
}

然后我尝试像这样使用这个API

interface Person {
firstName: string
lastName: string
}
const person: Person = { firstName:'John', lastName: 'Doe' }
const sessionId = 'test'
log('Hello', { person, sessionId })

person字段不起作用,因为我得到了这个错误:

Index signature for type 'string' is missing in type Person

如何修改日志函数的签名和/或LogMetadata类型的定义以使其工作,但仍然限制调用仅使用原语、对象和数组构建的简单类型(不包括函数、符号和其他可能在日志中工作不好的东西)。

我相信你正在寻找的是这个,它使用条件类型。原始类型是任何您可能认为是原始类型的联合。然后logMetaData将是泛型的,它的每个键与传入的类型T相同。

每个键的值都是条件类型,我们做以下检查:

如果T[key]是一个对象,那么我们需要该对象的元数据。

否则,检查T[key]是否为Array,如果是,则使该值为该数组类型的元数据数组。

最后,如果不符合上述条件,则必须为原语。

type Primitive = boolean | number | string | undefined;
type LogMetadata<T> = {
[key in keyof T]: 
T[key] extends Object ? 
LogMetadata<T[key]> : 
T[key] extends Array<unknown> ?
Array<LogMetadata<T[key][number]>> :
Primitive;
}
type Person = {
firstName: string;
lastName: string;
pets: string[],
friends: Person[];
}
const person: Person = { firstName:'John', lastName: 'Doe', pets: ["dog", "cat"], friends: [
{
firstName: "Billy",
lastName: "Bob",
pets: [],
friends: [],
}
] }
const myMetadata: LogMetadata<Person> = { ...person }

最新更新