简体   繁体   English

TypeScript,JavaScript:如何通过循环typeof动态创建组合类型?

[英]Typescript, javascript: how to create a combined type dynamically via looping typeof?

Suppose we have: 假设我们有:

const array = [a, b, c]  // could be any number of items in here
type T = ???  // how to write this?

such that the result is equivalent to 这样结果等于

type T = typeof a & typeof b & typeof c

except T is dynamically created based on looping through array (since array may actually have items other than a , b , c ). 除了T是基于遍历数组动态创建的(因为array实际上可能具有abc以外其他项)。 A solution using interfaces may be acceptable as well. 使用接口的解决方案也是可以接受的。

If the array is typed correctly it will be typed as a union of the element types. 如果正确键入数组,则将其作为元素类型的并集键入。 Ex: 例如:

let a = { aProp: 1 };
let b = { bProp: 1 };
let c = { cProp: 1 };
const array = [a, b, c]  // typed as ({ aProp: number; } | { bProp: number; } | { cProp: number; })[]

Starting from this we can transform the union to an intersection using conditional types (see this answer for an explanation of UnionToIntersection ) and use a type query to get the type of an item in the array: 从此开始,我们可以使用条件类型将并集转换为相交(请参见此答案以获取UnionToIntersection的说明),并使用类型查询来获取数组中项的类型:

type UnionToIntersection<U> = 
    (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

type T = UnionToIntersection<typeof array[number]>  // { aProp: number; } & { bProp: number; } & { cProp: number; }

Typescript types only exist at compile time, they will be removed at runtime (making it javascript). Typescript类型仅在编译时存在,它们将在运行时被删除(使其变为javascript)。 As the values of the array only exist at runtime, there is no way to get their type on compile-time. 由于数组的值仅在运行时存在,因此无法在编译时获取其类型。

Okay, so I couldn't get @Titian's answer to work; 好的,所以我无法得到@Titian的答复; here's another solution 这是另一种解决方案

type Intersect<T extends any[]> = {[key in keyof T[number]] :T[number][key]};

And you can use it like this, say 你可以像这样使用它 在此处输入图片说明 See how the IDE knows its properties, and it error's if you try to assign anything else! 请查看IDE如何知道其属性,如果尝试分配其他任何内容,就会出错!


Unfortunately it thinks they are optional, you can combat this if you force them all to be real. 不幸的是,它认为它们是可选的,如果您强制所有这些都是真实的,则可以解决此问题。

type Defined<T> = T extends (undefined|void) ? never : T;
type Intersect<T extends any[]> = {[key in keyof T[number]] :Defined<T[number][key]>};

The issue here is if you have a type that is {optional ?:string} , I think you'll lose that nuance. 这里的问题是,如果您的类型是{optional ?:string} ,那么我认为您会失去细微差别。


I thought that simple & s would solve this issue, but it doesn't (and adds an upper bound to the size of your 'dynamic' array; in this case I could only be bothered copy-pasting for 6-length arrays). 我以为simple & s可以解决此问题,但不能解决(并为“动态”数组的大小增加了上限;在这种情况下,我只能为复制6长度的数组而烦恼)。

type Intersect<T extends any[]> =
    T[5] extends void ? T[4] extends void ? T[3] extends void ? T[2] extends void ? T[1] extends void ? T[0] extends void ?
    [] : T[0] : T[0]&T[1] : T[0]&T[1]&T[2] : T[0]&T[1]&T[2]&T[3] : T[0]&T[1]&T[2]&T[3]&T[4] : T[0]&T[1]&T[2]&T[3]&T[4]&T[5]
;

I feel like the real solution will be when they figure out recursive types. 我觉得真正的解决方案是当他们找出 递归类型时。

type Head<T> = T extends [infer U, ...Array<unknown>] ? U : never;
type Tail<T> = T extends any[] ?
    (...args :T) => any extends (head :any, ...args :infer U) => any ?
        U :
        never
    :
    never
;
type Intersect<T extends any[]> = T[1] extends void ? T[0] : Head<T>&Intersect<Tail<T>>;

Head & Tail (which can pull the first type of an array, and the remaining types as a new array type respectively) both work, but Intersect breaks when it refers back to Intersect . HeadTail (其可以拉动第一类型的数组的,其余类型作为新的数组类型分别地)两个工作,但Intersect时,它是指回打破Intersect

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM