#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);