typescript - Differentiera returtyp baserat på argument


Jag försöker skriva en funktion som antingen accepterar en sträng eller string[] och returnerar antingen en bool eller bool[] respektive. Jag har försökt både med generiska typer och överlagring, men båda verkar ge någon form av fel:

// generic way
function genericWay<T extends string | string[]>(val: T): T extends string ? boolean : boolean[] {
    if (typeof val === 'string'){
        return true // Type 'true' is not assignable to type 'T extends string ? boolean : boolean[]'
    }
    return [true] // Type 'true[]' is not assignable to type 'T extends string ? boolean : boolean[]'
}

const a1 = overloadWay('bbb')
const a2 = genericWay(['bbb'])
const a3 = genericWay(5333) // should throw error


// overload way
function overloadWay(val: string[]): boolean[]; // This overload signature is not compatible with its implementation signature.
function overloadWay(val: string): boolean {    
    if (typeof val === 'string'){
        return true
    }
    return [true] // Type 'boolean[]' is not assignable to type 'boolean'.
}

const b1 = overloadWay('bbb')
const b2 = overloadWay(['bbb'])
const b3 = overloadWay(5333) // should throw error

ts lekplats

  1. Från det första exemplet - verkar det som att min returtyp är fel?
  2. För överbelastningssättet, av någon anledning fångar det inte upp typkontrollen för att skilja mellan de två indatatyperna.

Svar #1

Eftersom ett annat svar redan ger hur man fixar varningen på det generiska sättet, vilket kräver explicit typkonvertering, här är hur du kan använda funktionsöverlagring för att uppnå samma mål.

Din definition av överbelastning är inte korrekt. Du behöver ange alla överbelastningar före funktionen och den implementerande funktionen bör innehålla alla möjliga in- och utgångar i sin signatur. Du kan använda any i implementeringen, men jag tror inte att det är rekommenderat där du kan undvika det.

Här är det överbelastade sättet

// overload way
function overloadWay(val: string[]): boolean[];
function overloadWay(val: string): boolean ;
function overloadWay(val: string| string[]): boolean | boolean[] {    
    if (typeof val === 'string'){
        return true
    }
    return [true]
}

// b1 is boolean
const b1 = overloadWay('bbb')

// b2 is boolean[]
const b2 = overloadWay(['bbb'])

// shows error
const b3 = overloadWay(5333) 

TS Lekplats

Svar #2

Jag har gjort några ändringar på det generiska sättet, för att ha en separat generisk typ, och fastställt den returnerade värdets typ med as, kolla här

type genType<T> = T extends string ? boolean : boolean[];

function genericWay<T extends string | string[]>(val: T): genType<T> {
    if (typeof val === 'string'){
        return true as genType<T>
    }
    return [true] as genType<T>
}

const a1 = genericWay('bbb')
const a2 = genericWay(['bbb'])
const a3 = genericWay(5333) // should throw error

Relaterade artiklar