Reputation: 3781
I have the following function call:
this.get('barcode').scan();
Is it possible to define the get function in a way that the return type is determined by the value of the function argument. In my case 'get' returns the Barcode class if called with 'barcode' and the Mqtt class if called with 'mqtt'.
Upvotes: 8
Views: 2521
Reputation: 1294
Yes, as of Typescript 3.2 you can use conditional types to do the trick:
const get = <T extends "barcode" | "mqtt">(s: T) =>
s === "barcode" ?
<T extends "barcode" ? {scan: () => string} : {pan: () => string}>{scan: () => "we are scanning"} :
<T extends "barcode" ? {scan: () => string} : {pan: () => string}>{pan: () => "we are panning"}
get("barcode").scan() // OK
get("mqtt").pan() // OK
get("barcode").pan() // Error
Note: I did not succeed in moving the casts to the function's return type - this will have to be put in another question for the real experts.
Upvotes: 1
Reputation: 221392
Yes, you can use overload on strings to do this. Example:
interface BarcodeScanner { scan(): number; }
interface Accelerometer { getAcceleration(): number; }
class MyClass {
get(name: 'accelerometer'): Accelerometer;
get(name: 'barcode'): BarcodeScanner;
get(name: string): any; // Fallback string signature
get(name: string): any { // Implementation signature, not visible
/* ... */
return undefined;
}
something() {
let x = this.get('barcode');
x.scan(); // OK
let y = this.get('accelerometer');
y.getAcceleration(); // OK
}
}
Upvotes: 8
Reputation: 23772
It's not possible to statically determine a type in function of a (dynamic) string. But generics are made for these cases.
Example:
class MyClass {
public get<T>(type: string): T {
// ...
}
public anotherMethod() {
this.get<Barcode>('barcode').scan();
}
}
I'm not sure to understand the problem with Ember, but if the method get
is dynamically inserted in the object, then maybe a solution like this:
class MyClass {
public get: function<T> (type: string): T; // this is just a static declaration, there is no generated JS code here
public anotherMethod() {
this.get<Barcode>('barcode').scan();
}
}
Upvotes: 2