typescript 2.8 Exclude: möjligt att förstärka 'partition'-typen?
Jag skulle vilja förbättra typen av partitionsfunktionen i mitt TS-bibliotek.
Om man tillämpar det på Array, är typen:
function partition<T>(list: T[], predicate:(x:T)=>boolean): [T[],T[]];
Och ett exempel på anrop skulle vara:
[1,2,3,4].partition(x => x%2===0)
=> [[2,4],[1,3]]
Nu lägger TypeScript 2.8 till villkorstyper, och i synnerhet Exclude (observera att TypeScript 2.8 vid denna tidpunkt endast är i kandidatsläppsstadiet).
Så min idé för att förbättra typen av partition, så att det är möjligt att dra nytta av typvakter, skulle vara något i den stilen:
function partition<T>(list: T[], predicate:(x:T)=>boolean): [T[],T[]];
function partition<T,U extends T>(list: T[], predicate:(v:T)=>v is U): [U[],Array<Exclude<T,U>>];
Tyvärr kan jag inte få detta att kompileras med --strict med TypeScript 2.8rc.
Här är ett exempelprogram:
function partition<T>(list: T[], predicate:(x:T)=>boolean): [T[],T[]];
function partition<T,U extends T>(list: T[], predicate:(v:T)=>v is U): [U[],Array<Exclude<T,U>>];
function partition<T,U extends T>(list: T[], predicate:(v:T)=>v is U): [U[],Array<Exclude<T,U>>] {
return <any>[];
}
Kompilera med TS 2.8rc med --strict för att återskapa byggfelet, vilket är:
test.ts(2,10): error TS2394: Overload signature is not compatible with function implementation.
Om man tittar på definitionen av Exclude har jag också försökt ändra den andra definitionen så att den returnerar, istället för [T[],T[]], snarare [T[], Array<T|never>>], men det hjälpte inte, jag får fortfarande samma fel.
Är det möjligt att uppnå det jag vill med TypeScript 2.8?
UPPDATERING Titian Cernicova-Dragomirs svar får det att fungera, men det var på det reducerade testfallet, det fungerar fortfarande inte för mig i en klass:
class Vector<T> {
partition<U extends T>(predicate:(v:T)=>v is U): [Vector<U>,Vector<Exclude<T, U>>];
partition(predicate:(x:T)=>boolean): [Vector<T>,Vector<T>];
partition<U extends T>(predicate:(v:T)=>boolean): [Vector<U>,Vector<Exclude<T, U>>] {
return <any>[];
}
}
Tydligen utlöser det extra kontroller eller något liknande att göra det i en klass, eftersom det är samma kod som fungerar utanför en klass...
Det här fungerar:
class Vector<T> {}
function partition<T,U extends T>(list: Vector<T>, predicate:(v:T)=>v is U): [Vector<U>,Vector<Exclude<T, U>>];
function partition<T>(list: Vector<T>, predicate:(x:T)=>boolean): [Vector<T>,Vector<T>];
function partition<T,U extends T>(list: Vector<T>, predicate:(v:T)=>boolean): [Vector<U>,Vector<Exclude<T, U>>] {
return <any>[];
}
Men bara att lägga koden i klassen gör att det går sönder...
Svar #1
Din implementeringssignatur behöver vara lite mer inkluderande, predikatet kan inte vara en typvakt, eftersom det i vissa överlagringar inte är en typvakt. Även ordningen på överlagringarna behöver vara annorlunda, eftersom den första kommer att fånga alla fall som den andra gör, signaturer betraktas i deklarationsordning.
function partition<T,U extends T>(list: T[], predicate:(v:T)=>v is U): [U[],Array<Exclude<T, U>>];
function partition<T>(list: T[], predicate:(x:T)=>boolean): [T[],T[]];
function partition<T,U extends T>(list: T[], predicate:(v:T)=>boolean): [U[],Array<Exclude<T, U>>] {
return <any>[];
}
// Usage
declare let arr: (string| number)[];
function isNumber(n: string| number) : n is number {
return typeof n === 'number';
}
let k = partition(arr, isNumber) // will be [number[], string[]]
För Vector-exemplet kan signaturen använda Vector<any> som kommer att vara kompatibel med både Vector<T> och Vector<Exclude<T, U>>. Jag är inte säker på varför det är tillåtet i det första exemplet men inte i detta.
class Vector<T> {
partition<U extends T>(predicate:(v:T)=>v is U): [Vector<U>,Vector<Exclude<T, U>>];
partition(predicate:(x:T)=>boolean): [Vector<T>,Vector<T>];
partition<U extends T>(predicate:(v:T)=>boolean): [Vector<U>,Vector<any>] {
return <any>[];
}
}
declare var v: Vector<string| number>;
function isNumber(n: string| number) : n is number {
return typeof n === 'number';
}
var d = v.partition(isNumber) // will be [Vector<number>, Vector<string>]
