typescript - 有没有办法撤销接口继承,即从派生接口中剥离基接口?
在 Typescript 中,我有一个接口 B,它继承自接口 A。
interface A {
a: "a",
b: "b"
}
interface B extends A {
c: "c",
d: "d"
}
我想写一个泛型,它可以“剥离”A中的B,即可以给我一个只包含B中指定部分的类型,而不包含从A继承的部分。
type StripType<T2, T1> = ??
type C = StripType<B, A>; // { c: "c", d: "d" }
在这种情况下,非常简单,我可以这样写 StripType,它就能工作:
type StripType<T2, T1> = Omit<T2, keyof T1>;
然而,当使用更复杂的继承时,这种实现将不再起作用:
type R = Record<string, string>;
interface D extends R {
e: "e"
}
type E = StripType<D, R>; // { [x: number]: string } <--- I want it to be { e: "e" }
我如何重写 StripType 以使其更健壮?我已经尝试了很多方法,但到目前为止都没有成功。请注意,最好能有一个通用的解决方案,但如果不可能,那么一个只能够去除 Record<string, string> 的方法也会有用,因为这是我实际的使用场景。
答案#1
- 将键提取为两种类型的元组,例如
string和e不会组合在一起。 - 查找公共键并从
D中提取差异 - 创建一个具有不同键的映射类型。
操场
type Keys<D> = {[K in keyof D as number]: [K]}[number];
type CommonKeys<T, U> = T extends [any] ? U extends [any] ? [T[0], U[0]] extends [U[0], T[0]] ? T : never : never: never;
type DiffKeys<T, U> = T extends [unknown] ? IsExactlyInUnion<T, U> extends never ? T : never: never;
type StripTypes<A, B, K = Keys<A>, C = CommonKeys<Keys<A>, Keys<B>>> =
{[P in DiffKeys<K, C> as P extends [any] ? P[0] : never]: P extends [any] ? A[P[0]] : never};
type IsExact<T, U> = [T] extends [U] ? ([U] extends [T] ? true : false) : false;
type IsExactInUnion<T, U> = U extends any ? IsExact<T, U> extends true ? true : never : never;
type IsExactlyInUnion<T, U> = [IsExactInUnion<T, U>] extends [never] ? never : T;
type R = Record<string, string> & {a: 'a'}
interface D extends R {
e: 'e',
}
type dKeys = Keys<D>;
type rKeys = Keys<R>;
type commonKeys = CommonKeys<Keys<D>, Keys<R>>;
type dDiff = DiffKeys<Keys<D>, CommonKeys<Keys<D>, Keys<R>>>
type E = StripTypes<D, R>; // type E = {e: "e";}
type R2 = {a: 'a'}
interface D2 extends R2 {
e: 'e',
[x: string]: any
}
/*
type E2 = {
[x: string]: any;
e: "e";
}
*/
type E2 = StripTypes<D2, R2>;
// a possible edge case when values are the same
type R3 = {[x: string]: 'e'}
interface D3 extends R3 {
e: "e",
}
type E3 = StripTypes<D3, R3>; // type E = {e: "e";}
