1

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()
MoreThanTom
  • 526
  • 2
  • 9
  • Typescript 3.2 makes it easier to narrow union types. Take a look at https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-2.html#non-unit-types-as-union-discriminants. – ford04 Feb 22 '19 at 06:38

5 Answers5

1

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()
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
1
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
Nathan Xabedi
  • 1,097
  • 1
  • 11
  • 18
1

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

MoreThanTom
  • 526
  • 2
  • 9
0

It has to be dealt with do_one() function basically

getInterface(<someparam>):number{
   do_one():number{
      return 4;
   }
}
let res:number = one.do_one();
manish kumar
  • 4,412
  • 4
  • 34
  • 51
0

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.

Mukundhan
  • 3,284
  • 23
  • 36
  • I'm not writing any javascript at all here. I'm trying to define the typings for an enviroment where a call to methodA(parameters) returns different objects depending on the value of parameters.type. I'd know how to do this if I could just write it in javascript :P – MoreThanTom Feb 22 '19 at 05:57