Typescript-type-definisjon for RegExpMatchArray med en streng nullsjekk
Problem
Jeg har litt problemer med et iterable objekt (hvis jeg forstår det riktig) i Typescript streng modus (streng nullsjekk). Jeg vil bruke det returnerte objektet fra 'String.prototype.match()'.
const matchLetter: RegExpMatchArray | null = points[0].match(/[a-zA-Z]/);
const direction: Tdirection = matchLetter[0];
// Two errors:
// 1. Object is possibly 'null'. ts(2531)
// 2. Type 'string' is not assignable to type 'Tdirection'. ts(2322)
Hva jeg prøver å gjøre:
// don't change RegExpMatchArray, it's from typescript lib.es5.d.ts
interface RegExpMatchArray extends Array<string> { index?: number; input?: string; }
// custom types
type Tlocation = { x: number; y: number };
type Tdirection = "R" | "U" | "L" | "D";
// demo data
const pathToPlot = [["R0", "R1", "R2"],["U0", "U1"],["L0"],["D0"]];
// demo operations
const operations = {
R: (index: number, lastLocation: Tlocation) => { return { x: lastLocation.x + index, y: lastLocation.y }},
U: (index: number, lastLocation: Tlocation) => { return { x: lastLocation.x + index, y: lastLocation.y }},
L: (index: number, lastLocation: Tlocation) => { return { x: lastLocation.x - index, y: lastLocation.y }},
D: (index: number, lastLocation: Tlocation) => { return { x: lastLocation.x, y: lastLocation.y - index }}
};
pathToPlot.forEach(points => {
// In JS I did it like this:
// const direction = points[0].match(/[a-zA-Z]/)[0];
// Typescript equivalent?
const matchLetter: RegExpMatchArray | null = points[0].match(/[a-zA-Z]/);
// This is giving errors:
const direction: Tdirection = matchLetter[0];
// two errors:
// 1. Object is possibly 'null'. ts(2531)
// 2. Type 'string' is not assignable to type 'Tdirection'. ts(2322)
console.log(operations[direction](1, { x: 0, y: 0 }));
});
Live kodeeksempel: https://codesandbox.io/s/reverent-thunder-s2wzn
Det jeg har gjort så langt:
Jeg har lest et par artikler om dette emnet.
Et forslag var å definere en ny type for RegExpArray (beskrevet her). Men det virker merkelig å definere en eksisterende type på nytt. Jeg vil heller bruke den eksisterende og utføre min egen logikk rundt den for å få det til å fungere.
Jeg leste også artikkelen "Hvordan unngå null-sjekk-forurensning i Javascript: bruk Optionals" (artikkel). Den sier at du kan bruke et bibliotek som gir en metode for å sjekke om verdien er null. Hvis det er tilfelle, håndterer det det med en feilmelding og deretter returnerer det noe annet.
Finnes det ikke en måte uten bruk av et bibliotek?
Svar #1
Du må sjekke for null først:
const matchLetter: RegExpMatchArray | null = points[0].match(/[a-zA-Z]/);
if (matchLetter) {
const direction: Tdirection = matchLetter[0];
}
Hvis Typescript ikke automatisk gjenkjenner at matchLetter-verdien allerede er sjekket, gjør det eksplisitt:
const matchLetter: RegExpMatchArray | null = points[0].match(/[a-zA-Z]/);
if (matchLetter) {
const direction: Tdirection = matchLetter![0] as Tdirection;
}
Den etterfølgende ! er en såkalt non-null-assertion-operator som gjør det eksplisitt at en nullable variabel vil inneholde en verdi på dette punktet. Typescript bør ikke kreve det hvis vi har typevokteren før tilgangen til matchLetter. Men jeg har sett tilfeller hvor Typescript-linteren fortsatt klaget.
Feilen på direction er tydelig siden du prøver å tilordne en generell streng til en streng-enumerasjon. Jeg har endret koden ovenfor til å bruke et as-kast for å stilne linteren.
Når du har endret direction-tildelingen, må du også endre operations-uttrykket på slutten:
var direction: Tdirection | undefined;
if (matchLetter) {
direction = matchLetter[0] as Tdirection;
}
if (direction) {
console.log(operations[direction](1, { x: 0, y: 0 }));
}
