我想实现类型的条件行为。当我将泛型以对象类型(数组,对象,元组,记录),实际上是任何复合类型的形式放置时,我希望该类型表现为该对象的typeof字段,但是当给定类型是主类型时,我想是同一类型。
type B<A> = A extends object ? A[keyof A] : A;
const tuple: [1, 2];
const element:B<typeof tuple> = 2; // # ISSUE - element can be also any method of array
const num: 1;
const numElment:B<typeof num> = 1;
以上代码可以使用,但是对于复合B
类型,我还可以分配Array类型中的所有方法类型。我的问题是-如何指定我只对不是功能的东西感兴趣。因此,只有纯字段(例如以元组为例,element
才应该是数字。
我也尝试使用extends {}
或extends {[a: string | number]: any}
,但是它也没有用,甚至在以上代码段之后也会中断。
答案 0 :(得分:1)
如果您确实想从类型联合中排除函数,则可以使用Exclude<T, U>
utility type:
type ExcludeFunctionProps<T extends object> = Exclude<T[keyof T], Function>;
但是我不认为这确实可以满足您的要求:
type Hmm = ExcludeFunctionProps<["a", "b"]>; // "a" | "b" | 2
这里Hmm
是"a" | "b" | 2
。为什么2
?因为数组具有数字类型的length
属性,而对元组具有该类型作为数字文字类型2
。除非您打算包括元组的长度,否则可能不是这样。
type EvenWeirder = ExcludeFunctionProps<[string, () => void]>; // string | 2
在元组或对象显式包含类似函数的值的情况下,这也会将它们切掉。在我看来,这绝对是一种奇怪的行为。
相反,我认为您遇到了the issue,其中keyof T
仍然是所有数组方法和属性的完整列表,即使您可以map over array types没有它们。因此,我在这里尝试做的是制作自己的KeyofAfterMapping<T>
,对于非数组类型返回keyof T
,但对于数组类型仅保留number
索引键。像这样:
type KeyofAfterMapping<T> = Extract<
keyof T,
T extends any[] ? number : unknown
>;
让我们看看它的作用:
type KeyofPair = KeyofAfterMapping<["a", "b"]>; // number
type KeyofArray = KeyofAfterMapping<string[]>; // number
type KeyofObject = KeyofAfterMapping<{ a: string; b: number }>; // "a" | "b"
现在我们可以指定B
:
type B<A> = A extends object ? A[KeyofAfterMapping<A>] : A;
并验证其行为是否符合您的预期:
type TryTupleAgain = B<["a", "b"]>; // "a" | "b"
type KeepsFunctions = B<Array<() => void>>; // () => void
type ObjectsAreStillFine = B<{ a: string; b: number }>; // string | number
type PrimitivesAreStillFine = B<string>; // string
看起来不错。好的,希望对您有所帮助。祝你好运!