Reputation: 2676
Using a generic typed class, I would like some methods to be available ONLY IF generic type is 'string'.
With the following code
class MyClass<T = string> {
value: T = null;
setDate(m: Moment) {
// could be used only if T is string
value = m ? m.format('YYYY-MM-DD') : null;
}
}
gives me the error
Argument of type 'string' is not assignable to parameter of type 'T'
which is really clear and totally intended : Moment.format()
returns a string
. :D
Is there a proper way to make the setDate()
method avaible only if T
is string
?
By advance, thank you very much.
I know I can fix the problem using m.format('YYYY-MM-DD') as unknown as T
but it looks like a workaround, not a real typescript solution.
And I know about Conditional Types but I don't think it could fix my problem. At least, I did not find how to figure it out.
Upvotes: 2
Views: 675
Reputation: 33104
To extend on Dimava's solution, you can set the type of this
to never
whenever the method should not exist:
class MyClass<T = string> {
setDate(
this: T extends string ? MyClass<T> : never,
m: Moment
) {
...;
}
}
The advantage of this strategy is that it works even for methods that don't take any arguments.
Note that this: Type
is a special TypeScript syntax to type the this
object. The this
pseudo-parameter gets removed by TypeScript compiler, so the JavaScript engine never sees it.
Upvotes: 2
Reputation: 10899
make function have never
arg on incorrect generic
type Moment = {format(s:string):string};
type SimpleEquals<T, V> = [T] extends [V] ? [V] extends [T] ? true : false : false;
class MyClass<T = string> {
value: T | null = null;
// could be used only if T is string
setDate(m: SimpleEquals<T, string> extends true ? Moment : never) {
this.value = m ? m.format('YYYY-MM-DD') as T : null;
}
}
declare let m: Moment;
new MyClass<string>().setDate(m) // ok
new MyClass<number>().setDate() //err
new MyClass<number>().setDate(m) //err
new MyClass<string | number>().setDate() //err
new MyClass<string | number>().setDate(m) //err
new MyClass<'qwe'>().setDate() //err
new MyClass<'qwe'>().setDate(m) //err
Upvotes: 3