Тип условного возврата машинописного текста для функции

#typescript #typescript-typings #typescript-generics

Вопрос:

У меня есть функция, которая может возвращать два типа, что-то вроде этого:

 function doSomething(obj: {a: string, b?: string}): string | number {
  if (obj.b) {
    return 'something'
  }
  return 1
}
 

Если функция вызывается с объектом, содержащим необязательное b свойство, она всегда возвращает один тип, в данном случае, скажем string так .

Если функция вызывается с объектом , который не содержит необязательного свойства b , она всегда будет возвращать другой тип, в данном случае, скажем number .

В настоящее время, если я вызову функцию, тип возвращаемого значения всегда будет объединением string и number :

 const result = doSomething({a: 'a', b: 'b'})
//      ^ string | number
// although we know it is always going to be a string if the `b` property is given
 

Есть ли способ, чтобы функция возвращала правильный тип в зависимости от аргумента, заданного функции?

 const result1 = doSomething({a: 'a', b: 'b'})
//      ^ string

const result2 = doSomething({a: 'a'})
//      ^ number
 

Я пытался сделать это с помощью условных типов, но мне это не удалось, и я не знаю, на правильном ли я пути:

 type ConditionalType<T> = T extends { b: string} ? string : number
type Argument = {
  a: string,
  b?: string,
}

function doSomething<T extends Argument>(obj: T): ConditionalType<T> {
  if (obj.b) {
    return 'something' // type string is not assignable to ConditionalType<T>
  }
  return 1 // type number is not assignable to ConditionalType<T>
}

const result = doSomething({a: 'a', b: 'b'})
 

Также пытался разрешить TypeScript определять тип, но в результате все равно получается тип объединения:

 function doSomething(obj: {a:string,b?:string}) {
  if (obj.b) {
    return 'something'
  }
  return 1
}

const result = doSomething({a: 'a', b: 'b'})
//      ^ "something" | 1
 

Игровая площадка для машинописи

Комментарии:

1. Вот самое близкое, что у меня есть: typescriptlang.org/play? #код/…

Ответ №1:

Кажется, это работает. Это чистая перегрузка функций:

 function doSomething(obj: {a:string,b?:string}): string;
function doSomething(obj: {a:string,b?:undefined}): number;
function doSomething(obj: {a:string,b?:string}): string|number {
  if (obj.b) {
    return 'something'
  }
  return 1
}

const result1 = doSomething({a: 'a', b: 'b'})
//      ^ "something" | 1
console.log(result1);

const result2 = doSomething({a: 'a'})
//      ^ "something" | 1
console.log(result2);
 

Детская площадка TS