I want to assign type to property of class that depends on passed property in argument. I wonder if it's possible.
Example:
enum MyEnum {
g,
f,
h,
}
interface MappedTypes {
[MyEnum.f]: X
[MyEnum.g]: Y
[MyEnum.h]: Z
}
class MyClass {
a: string // does not matter
b: something like MappedTypes[c]
c: MyEnum
constructor(params: { a: string; b: MappedTypes[<inherit from c>]; c: MyType }) {
// for example
// if c === MyEnum.g
// b must be Y as mapped in MappedTypes
}
}
One thing you can do is make your class generic in E
, the type of the c
property, and give b
a lookup type like MappedTypes[E]
. This is the closest I can get to the code you're writing now:
class MyClass<E extends MyEnum> {
a: string
b: MappedTypes[E]
c: E
constructor(params: { a: string; b: MappedTypes[E]; c: E }) {
this.a = params.a;
this.b = params.b;
this.c = params.c
}
}
Beware though that once you use a generic like this you might find it difficult inside the implementation of MyClass
to use b
and c
in a correlated way. See microsoft/TypeScript#13995 and microsoft/TypeScript#24085 for more information.
Another way to proceed here is to keep b
and c
bundled into a single params
property of a discriminated union type, like this:
type Params = { [K in MyEnum]: { a: string, b: MappedTypes[K], c: K } }[MyEnum]
If you examine Params
you'll see that it evaluates to the following union:
/*
type Params =
{ a: string; b: Y; c: MyEnum.g; } |
{ a: string; b: X; c: MyEnum.f; } |
{ a: string; b: Z; c: MyEnum.h; }
*/
And then you could define MyClass
like this:
class MyClassU {
constructor(public params: Params) { }
}
So instead of this.b
you'd need to refer to this.params.b
, which might be annoying. On the plus side, you will be able to do things like switch
on this.params.c
and the compiler will understand that it has an implication for the type of this.params.b
:
someMethod() {
switch (this.params.c) {
case (MyEnum.f): {
this.params.b; // known to be X
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.