打字稿类型:在类型定义中使用泛型的static readonly/const 属性
Typescript types: use static readonly/const property of generic type in type definition
我有这个class定义:
export class Entity {
a?: string;
b?: string;
c?: string;
static required = ['c'] as const;
}
基本上我想写一个类型定义,它将采用这种类型,并使用静态array required
,来生成c
的类型] 不是可选的。
我想这样做:
export type WithRequired<T extends Entity> = Partial<T> & Required<Pick<T, typeof T.required[number]>>;
但这失败并出现错误:
'T' only refers to a type, but is being used as a value here.
如果我通过将 T.required
替换为 Entity.required
来稍微更改定义,那么它不会给我一个错误:
export type WithRequired<T extends Entity> = Partial<T> & Required<Pick<T, typeof Entity.required[number]>>;
这在这种情况下有效..但这当然不是一个令人满意的解决方案,因为我必须为项目中“实体”的每个变体创建一个类型,而不是让一个通用类型来处理所有案例。
所以我实际上有 2 个问题,只要回答其中 1 个问题就会对我有很大帮助:
- 有没有办法根据 class 的静态常量数组来“要求”class 的属性?
- 有没有办法更改
T.required
周围的部分,以便打字稿不再向我抛出错误?
type Entity
是您的 class 实例的类型。 值 Entity
class 的构造函数,typeof Entity
是该构造函数的类型。
并且实例的类型完全与其构造函数的类型脱节。所以如果你只有实例类型,你无法知道构造函数的类型。
事实上,您可以像使用任何接口一样使用 classes 实例类型,这证明实例类型不知道它是由什么构造的。
class Foo { bar: string }
const foo: Foo = { bar: 'baz' } // works
但是,您可以反其道而行之,使用 InstanceType<typeof MyClass>
.
从构造函数类型派生实例类型
这意味着您必须捕获 constructor 类型作为泛型,因为这是您的静态值实际所在的位置。然后,您可以从该类型中提取 required
static 属性 并将其合并到实例类型中。
export type WithRequired<T extends typeof Entity> =
Partial<InstanceType<T>> &
Required<Pick<InstanceType<T>, T['required'][number]>>;
然后像这样使用:
type TestA = WithRequired<typeof Entity>
const testA1: TestA = { c: 'c'} // works
const testA2: TestA = { a: 'a' } // Property 'c' is missing in type '{ a: string; }' but required in type 'Required<Pick<Entity, "c">>'.(2322)
缺点是您必须传入 typeof MyClass
,这会稍微冗长一些。但是如果你想访问一个静态的 属性 那么你需要构造函数的类型,你无法绕过这个简单的事实。
我有这个class定义:
export class Entity {
a?: string;
b?: string;
c?: string;
static required = ['c'] as const;
}
基本上我想写一个类型定义,它将采用这种类型,并使用静态array required
,来生成c
的类型] 不是可选的。
我想这样做:
export type WithRequired<T extends Entity> = Partial<T> & Required<Pick<T, typeof T.required[number]>>;
但这失败并出现错误:
'T' only refers to a type, but is being used as a value here.
如果我通过将 T.required
替换为 Entity.required
来稍微更改定义,那么它不会给我一个错误:
export type WithRequired<T extends Entity> = Partial<T> & Required<Pick<T, typeof Entity.required[number]>>;
这在这种情况下有效..但这当然不是一个令人满意的解决方案,因为我必须为项目中“实体”的每个变体创建一个类型,而不是让一个通用类型来处理所有案例。
所以我实际上有 2 个问题,只要回答其中 1 个问题就会对我有很大帮助:
- 有没有办法根据 class 的静态常量数组来“要求”class 的属性?
- 有没有办法更改
T.required
周围的部分,以便打字稿不再向我抛出错误?
type Entity
是您的 class 实例的类型。 值 Entity
class 的构造函数,typeof Entity
是该构造函数的类型。
并且实例的类型完全与其构造函数的类型脱节。所以如果你只有实例类型,你无法知道构造函数的类型。
事实上,您可以像使用任何接口一样使用 classes 实例类型,这证明实例类型不知道它是由什么构造的。
class Foo { bar: string }
const foo: Foo = { bar: 'baz' } // works
但是,您可以反其道而行之,使用 InstanceType<typeof MyClass>
.
这意味着您必须捕获 constructor 类型作为泛型,因为这是您的静态值实际所在的位置。然后,您可以从该类型中提取 required
static 属性 并将其合并到实例类型中。
export type WithRequired<T extends typeof Entity> =
Partial<InstanceType<T>> &
Required<Pick<InstanceType<T>, T['required'][number]>>;
然后像这样使用:
type TestA = WithRequired<typeof Entity>
const testA1: TestA = { c: 'c'} // works
const testA2: TestA = { a: 'a' } // Property 'c' is missing in type '{ a: string; }' but required in type 'Required<Pick<Entity, "c">>'.(2322)
缺点是您必须传入 typeof MyClass
,这会稍微冗长一些。但是如果你想访问一个静态的 属性 那么你需要构造函数的类型,你无法绕过这个简单的事实。