使用打字稿泛型声明具有相同键但派生类型的类型
declare type with same keys but derived type using typescript generics
为了在 Angular 中编写单元测试时减少样板代码,我想使用 typescript 泛型的强大功能轻松声明基于现有类型的新类型。
例如,来自 class 例如:
class BaseClass {
member1: number;
member2: Observable<boolean>;
get getter1(): Observable<string> {return null};
method1(): void {};
}
我想使用这种表示法声明一个 "derived" 类型
type FakeClass = Fake<BaseClass>;
对应于此声明
interface FakeClass {
member2: Subject<boolean>;
getter1: Subject<string>;
}
换句话说,Fake<T>
应该:
- 仅保留类型为
Observable<any>
的键
- 将类型从
Observable<U>
更改为 Subject<U>
到目前为止,我能够保留正确的密钥并将类型从 Observable<U>
更改为 Subject<any>
type KeysWithTypesFlags<T, U> = {
[key in keyof T]: T[key] extends U ? key : never;
};
// KeysWithTypesFlags<SomeClass, Observable<any>> => interface {
// member1: never;
// member2: 'member2';
// getter1: 'getter1';
// method1: never;
// }
type KeysWithTypes<T, U> = KeysWithTypesFlags<T, U>[keyof T];
// KeysWithTypes<SomeClass, Observable<any>> => 'member2' | 'getter1'
type ObservableKeys<T> = KeysWithTypes<T, Observable<any>>;
// ObservableKeys<SomeClass> => 'member2' | 'getter1'
type Fake<T> = {
[key in ObservableKeys<T>]: Subject<any>;
};
// Fake<SomeClass> => {
// member2: Subject<any>; // I'd like Subject<boolean>
// getter1: Subject<any>; // I'd like Subject<string>
// }
但我想不出一种方法来保留原始 Observable 的泛型类型。要真正通用,它应该适用于任何类型的 Observable(即我们不能假设像示例中那样只有布尔值或字符串的 Observable)
知道如何实现吗?
使用infer
!
在条件类型中,您可以推断出泛型类型,例如 Observable<infer T>
.
type Fake<C> = {
[K in KeysWithTypes<C, Observable<any>>]: C[K] extends Observable<infer T> ? Subject<T> : never;
}
为了在 Angular 中编写单元测试时减少样板代码,我想使用 typescript 泛型的强大功能轻松声明基于现有类型的新类型。
例如,来自 class 例如:
class BaseClass {
member1: number;
member2: Observable<boolean>;
get getter1(): Observable<string> {return null};
method1(): void {};
}
我想使用这种表示法声明一个 "derived" 类型
type FakeClass = Fake<BaseClass>;
对应于此声明
interface FakeClass {
member2: Subject<boolean>;
getter1: Subject<string>;
}
换句话说,Fake<T>
应该:
- 仅保留类型为
Observable<any>
的键
- 将类型从
Observable<U>
更改为Subject<U>
到目前为止,我能够保留正确的密钥并将类型从 Observable<U>
更改为 Subject<any>
type KeysWithTypesFlags<T, U> = {
[key in keyof T]: T[key] extends U ? key : never;
};
// KeysWithTypesFlags<SomeClass, Observable<any>> => interface {
// member1: never;
// member2: 'member2';
// getter1: 'getter1';
// method1: never;
// }
type KeysWithTypes<T, U> = KeysWithTypesFlags<T, U>[keyof T];
// KeysWithTypes<SomeClass, Observable<any>> => 'member2' | 'getter1'
type ObservableKeys<T> = KeysWithTypes<T, Observable<any>>;
// ObservableKeys<SomeClass> => 'member2' | 'getter1'
type Fake<T> = {
[key in ObservableKeys<T>]: Subject<any>;
};
// Fake<SomeClass> => {
// member2: Subject<any>; // I'd like Subject<boolean>
// getter1: Subject<any>; // I'd like Subject<string>
// }
但我想不出一种方法来保留原始 Observable 的泛型类型。要真正通用,它应该适用于任何类型的 Observable(即我们不能假设像示例中那样只有布尔值或字符串的 Observable)
知道如何实现吗?
使用infer
!
在条件类型中,您可以推断出泛型类型,例如 Observable<infer T>
.
type Fake<C> = {
[K in KeysWithTypes<C, Observable<any>>]: C[K] extends Observable<infer T> ? Subject<T> : never;
}