所以我正在尝试这种行为:
interface A {
prop1: string;
prop2: number;
prop3: boolean;
}
type PropertyArray<T> = magical code
// PropertyArray<A> should be the same as the type ['prop1', 'prop2', 'prop3']
const properties: PropertyArray<A> = ['prop1', 'prop2', 'prop3'];
const fail1: PropertyArray<A> = ['prop1', 'prop2']; // type error
const fail2: PropertyArray<A> = ['prop1', 'prop1', 'prop2', 'prop3']; // type error
此代码的要点是,如果我在接口A中添加新字段,则还需要将该属性包括在数组中。如果缺少任何属性,构建将失败。
感谢您的帮助。
答案 0 :(得分:1)
使用keyof
:
type PropertyArray = Array<keyof A>; // 'prop1' | 'prop2' | 'prop3'
type PropertyArray<T> = Array<keyof T>;
答案 1 :(得分:1)
如果您真的很在意财产顺序,那么如果您定义
,那么它实际上是this question about turning a union into a tuple的副本type PropertyArray<T> = TuplifyUnion<keyof T>
但是希望您实际上并不关心财产顺序,['prop2', 'prop1', 'prop3']
是properties
的可接受值。在这种情况下,我可以通过两种方式进行此操作:
一种方法是按照您的要求,将PropertyArray<T>
实际计算为元组中所有可能的键排列的并集。这自然会涉及循环条件类型which is not currently supported。相反,我可以定义一个支持类型的属性,该类型最多包含一些固定数量的属性,例如:
type PropertyArray<T> = Tup<keyof T>
type Cons<H, T extends any[]> = T extends any ? ((h: H, ...t: T) => void) extends ((...r: infer R) => void) ? R : never : never
type Tup<U, V = U> = [U] extends [never] ? [] : U extends any ? Cons<U, Tup1<Exclude<V, U>>> : never
type Tup1<U, V = U> = [U] extends [never] ? [] : U extends any ? Cons<U, Tup2<Exclude<V, U>>> : never
type Tup2<U, V = U> = [U] extends [never] ? [] : U extends any ? Cons<U, Tup3<Exclude<V, U>>> : never
type Tup3<U, V = U> = [U] extends [never] ? [] : U extends any ? Cons<U, Tup4<Exclude<V, U>>> : never
type Tup4<U, V = U> = [U] extends [never] ? [] : U extends any ? Cons<U, Tup5<Exclude<V, U>>> : never
type Tup5<U, V = U> = [U] extends [never] ? [] : U extends any ? Cons<U, Tup6<Exclude<V, U>>> : never
type Tup6<U, V = U> = [U] extends [never] ? [] : U extends any ? Cons<U, Tup7<Exclude<V, U>>> : never
type Tup7<U, V = U> = [U] extends [never] ? [] : U extends any ? Cons<U, Tup8<Exclude<V, U>>> : never
type Tup8<U, V = U> = [U] extends [never] ? [] : U extends any ? Cons<U, Tup9<Exclude<V, U>>> : never
type Tup9<U, V = U> = [U] extends [never] ? [] : U extends any ? Cons<U, TupX<Exclude<V, U>>> : never
type TupX<U> = [] // bail out
对于您的情况:
interface A {
prop1: string;
prop2: number;
prop3: boolean;
}
const properties: PropertyArray<A> = ['prop1', 'prop2', 'prop3'];
const fail1: PropertyArray<A> = ['prop1', 'prop2']; // type error
const fail2: PropertyArray<A> = ['prop1', 'prop1', 'prop2', 'prop3']; // type error
这可以按您想要的方式工作,但是对于编译器来说是很多工作,并且可能很脆弱。
不太疯狂的解决方案(仍然有点疯狂)是使用辅助函数而不是类型别名。仅在辅助函数的参数完全包含一次相关对象类型的每个键的情况下,该函数才会编译:
type TupleHasRepeats<T extends any[]> = { [I in keyof T]: T[I] extends T[Exclude<keyof T, keyof any[] | I>] ? unknown : never}[number]
const propertyArray = <T>() => <A extends Array<keyof T>>(...a: A & (keyof T extends A[number] ? unknown : never) & (unknown extends TupleHasRepeats<A> ? never : unknown )) => a;
然后尝试:
interface A {
prop1: string;
prop2: number;
prop3: boolean;
}
const propertyArrayA = propertyArray<A>();
const properties = propertyArrayA('prop1', 'prop2', 'prop3');
const fail1 = propertyArrayA('prop1', 'prop2'); // type error;
const fail2 = propertyArrayA('prop1', 'prop1', 'prop2', 'prop3'); // type error
也可以。如果我必须在生产代码中执行任何操作,则可能会使用后者。
好的,希望能有所帮助;祝你好运!
答案 2 :(得分:0)
如果需要A接口数组,则只需执行以下操作:
const properties: A[] = [ { 'string', 0, true }, { 'string', 1, false } ];
如果您的问题正确,请告诉我。
谢谢