Reputation: 526
Is there any way to define getInterface
in this context so that res has the type number
?
To clarify: I am not trying to write these methods, I have an enviroment where a method exists which returns different objects depending on parameters.type, and I'm trying to find a way to type them
interface A {
tag: 'a'
do_one: () => number;
}
interface B {
tag: 'b'
do_one: () => string;
}
type Interface = A | B
let one = getInterface({ type: 'a' })
let res = one.do_one()
Upvotes: 1
Views: 128
Reputation: 526
Thankyou for all the help! I admit my question was a bit of a mess, I definitely should've been clearer.
Anyway, I managed to get the correct typing -
type FilterTag<T, U> = T extends { tag: U } ? T : never
type Interface<T> = FilterTag<A | B, T>
declare function getInterface<T extends string>(params: { type: T }): Interface<T>
which means that getInterface({ type 'X' })
will always return the right interface, and there is only one union type to edit whenever it needs to be changed
Upvotes: 1
Reputation: 1127
declare function getInterface(arg: { type: 'a' }): A;
declare function getInterface(arg: { type: 'b' }): B;
let one = getInterface({ type: 'a'} )
let res = one.do_one() // res is a number
Upvotes: 1
Reputation: 249466
While your question is not 100% clear, in my reading you what getInterface
to take the type and return the apropriate value based on the type.
You can do this using overloads or conditional types:
With overloads:
type Interface = A | B
function getInterface(v: { type: 'a' }): A
function getInterface(v: { type: 'b'}): B
function getInterface(v: { type: 'b'} | { type: 'a'}): A | B {
return null!
}
let one = getInterface({ type: 'a' })
let res = one.do_one()
With conditional types
interface A {
tag: 'a'
do_one: () => number;
}
interface B {
tag: 'b'
do_one: () => string;
}
type Interface = A | B
type GetJustTypes = Interface extends infer I ? I extends { tag: infer U } ? { tag: U } : never : never
function getInterface<T extends GetJustTypes>(v: T): Extract<Interface, T>
function getInterface(v: { tag: 'b' } | { tag: 'a' }): A | B {
return null!
}
let one = getInterface({ tag: 'a' })
let res = one.do_one()
Upvotes: 1
Reputation: 3457
We need to understand typings clearer, typings are present to avoid errors during compilation time. after compilation, the end result will be pure javascript.
As for your question, typing can be added only using or | condition which will be checked during compilation only.
Dynamic typing is a myth yet to be solved.
But there is a method instance-of which can be used.
Upvotes: 0
Reputation: 4692
It has to be dealt with do_one()
function basically
getInterface(<someparam>):number{
do_one():number{
return 4;
}
}
let res:number = one.do_one();
Upvotes: 0