typescript - Typ för icke-falskt, även kallat sanningsenligt
Finns det en typ för sanningsenlig i TypeScript?
Jag har denna metod:
Object.keys(lck.lockholders).length;
enqueue(k: any, obj?: any): void
Jag tror att det med TS finns ett sätt att kontrollera för tomma strängar '', förresten.
Och jag vill konvertera det till:
enqueue(k: Truthy, obj?: any): void
förutom att jag inte vet hur man definierar typen för Truthy.
Anledningen till att jag vill ha detta är att jag inte vill att användare ska ange null, undefined, '' osv. som nyckel till ett hash.
Svar #1
Jag är inte säker på varför du behöver detta, men det är intressant. Ärligt talat är det korta svaret: TypeScript är inte anpassat för detta och du skulle förmodligen ha bättre nytta av att göra kontroller vid körning och dokumentera din kod så att utvecklare är medvetna om att k-parametern bör vara sanningsenlig. Ändå, om du är inställd på att försöka tvinga TypeScript att göra något sådant här, läs vidare:
Obs: för att det nedan ska fungera, slå på kompilatoralternativet strictNullChecks. Det är ganska nödvändigt, eftersom det skulle vara ett problem att inte kunna skilja Truthy från Truthy | null | undefined.
Du kan nästan definiera falskt, vilket är som
type Falsy = false | 0 | "" | null | undefined
utom att NaN också är falsy, och TypeScript har inte ett numeriskt litteral för NaN (se microsoft/TypeScript#15135).
Även om du har Falsy som ovan, finns det inga negerade typer (se microsoft/TypeScript#4196) i TypeScript, så det finns inget sätt att uttrycka Truthy som "allt utom Falsy".
Du kan försöka använda villkorliga typer för att utesluta möjligen falska parametrar i enqueue(), men det är konstigt:
type DefinitelyTruthy<T> =
false extends T ? never :
0 extends T ? never :
"" extends T ? never :
null extends T ? never :
undefined extends T ? never :
T
declare function enqueue<T extends number | string | true | object>(
k: T & DefinitelyTruthy<T>,
obj?: any
): void
declare const str: string;
enqueue(str); // error, might be falsy
enqueue("a"); // okay
enqueue(1); // okay
enqueue(0); // error
enqueue(NaN); // error
enqueue(true); // okay
enqueue(false); // error
enqueue([]); //okay
enqueue({a: "hello"}); // okay
enqueue({}); // error, interpreted as type {} which could be an empty string:
const zilch = "" as {};
enqueue(zilch); // error, see?
Notera hur det inte tillåter något som det tror kan vara falskt, vilket möjligen är vad du försöker uppnå. Kan inte säga.
Uppdatera
Jag ser att du redigerade frågan för att klargöra att k-parametern egentligen borde vara en string (eller möjligen en symbol) och att det enda värde du behöver utesluta är den tomma strängen "". I så fall kan du förenkla ovanstående till:
type DefinitelyNotEmptyString<T> = "" extends T ? never : T
declare function enqueue<T extends string | symbol>(
k: T & DefinitelyNotEmptyString<T>,
obj?: any
): void
enqueue(""); // error
enqueue("a"); // okay
Allt det där är bra, men tyvärr finns problemet att om du skickar en generell string till enqueue() så kommer det att misslyckas, och ibland kan en utvecklare behöva göra det om värdet de använder för k-parametern inte är en strängliteral som de har specificerat:
declare const str: string; // comes from somewhere else
enqueue(str); // error! how do I do this?
För att hantera detta kan du försöka skapa en nominal typ som du kan använda för att identifiera för kompilatorn att ett värde har kontrollerats för tomhet, och sedan skapa ett användardefinierat typvakt för att begränsa en string till den typen:
type NotEmptyString = string & {"***NotEmptyString***": true};
function notEmptyString(x: string): x is NotEmptyString {
return x !== "";
}
Nu kan utvecklaren göra detta:
declare const str: string;
enqueue(str); // error, might be falsy
if (notEmptyString(str)) {
enqueue(str); // okay, str is NotEmptyString
}
Phu! Det är mycket hinder att hoppa igenom. Det är upp till dig om du tycker att det är värt det. Okej, hoppas det hjälper. Lycka till!
Svar #2
Det finns ingen Truthy-typ, MEN du kan utnyttja typvaktssystemet (typ-predikat) för att hjälpa TypeScript att förstå vad som verkligen är truthy och tilldela det truthy-typ!
Låt oss definiera Falsy-typen och den generiska isTruthy-funktionen:
type Falsy = false | 0 | '' | null | undefined;
// this is a type predicate - if x is `truthy`, then it's T
const isTruthy = <T>(x: T | Falsy): x is T => !!x;
Nu kan vi använda vår isTruthy-funktion för att hitta Truthy-värden och TypeScript kommer korrekt att tilldela "truthy"-typen till resultatet.
Exempel:
{ // removing boolean "false" type
const result: string | false = Math.random() > 0.5 ? 'a' : false;
const truthyResult: string = isTruthy(result) ? result : 'was false';
}
{ // filtering only numbers from array
const result: (number | undefined)[] = [42, undefined, 8, 16];
const truthyResult: number[] = result.filter(isTruthy);
}
{ // filtering only Promises from array
const result: (Promise<string> | null)[] = [Promise.resolve('a'), null, Promise.resolve('b'), Promise.resolve('c')];
const truthyResult: Promise<string>[] = result.filter(isTruthy);
}
