javascript - Array av blandede typer, men med minimum antall av en viss type i Array
La oss si at jeg vil håndheve streng typetolkning på et gitt array, slik at:
- Det kan inneholde et hvilket som helst antall (dvs. null eller flere)
number - Det må inneholde ett eller flere tall av
string
...og rekkefølgen av number og string i arrayen ikke betyr noe, slik at følgende arrayer er gyldige:
['foo', 1, 2, 3][1, 2, 'foo', 3]['foo']
Men følgende array er ugyldig:
[1, 2, 3](fordi det trenger minst énstringi arrayen)
Den nærmeste løsningen som nesten fungerte for meg, er å definere typen som:
/**
* Array must contain:
* - One or more string
* - Zero or more numbers
* @type
*/
type CustomArray = [string] & Array<number | string>
const a: CustomArray = ['foo', 1, 2, 3]; // Should pass (works as expected)
const b: CustomArray = [1, 2, 'foo', 3]; // Should pass (but doesn't with my code)
const c: CustomArray = ['string']; // Should pass (works as expected)
const d: CustomArray = [1, 2, 3]; // Should fail (works as expected)
Men dette betyr at det første elementet i arrayen må være en streng, i stedet for å håndheve en minimumsantall på 1 gjennom hele arrayen. Du kan teste det på TypeScript Playground her.
Svar #1
Det finnes ingen måte å fortelle TypeScript at et array skal inneholde minst ett element av en bestemt type.
Det beste du kan gjøre er bare å lage et tall-/streng-array:
type CustomArray = (number | string)[];
Eller
type CustomArray = Array<number | string>;
Og deretter legg til de nødvendige kontrollene der du legger til eller leser data til/fra arrayen.
Svar #2
Ville dette være en idé?
/**
* Array must contain:
* - One or more string
* - Zero or more numbers
* @type
*/
console.clear();
const CustomArray = (arr: Array<string | number>) => {
if (!arr.length) {
return new TypeError("Invalid: array should contain at least one element");
}
const oneString = arr.filter(v => v.constructor === String).length;
const wrongTypes = arr.filter(v => v.constructor !== Number && v.constructor !== String).length && true || false;
if (wrongTypes) {
return new TypeError(`Invalid: [${JSON.stringify(arr)}] contains invalid types`);
}
if (!oneString) {
return new TypeError(`Invalid: [${JSON.stringify(arr)}] should contain at least one String value`);
}
return arr;
};
type MyArray = Array<string | number> | TypeError;
const a: MyArray = CustomArray(['foo', 1, 2, 3]); // Should pass (works as expected)
const b: MyArray = CustomArray([1, 2, 'foo', 3]); // Should pass (works as expected)
const c: MyArray = CustomArray(['string']); // Should pass (works as expected)
const d: MyArray = CustomArray([1, 2, 3]); // Should fail (works as expected)
const log = (v:any) =>
console.log(v instanceof TypeError ? v.message : JSON.stringify(v));
log(a);
log(b);
log(c);
log(d);