typescript - Avgränsa ett objekt av typen okänd


Jag har läst flera inlägg och problem här med avseende på att begränsa ett object av typen unknown i TypeScript. Men jag har inte hittat denna specifika fråga eller lösning.

De flesta lösningar jag hittar säger att man ska göra något som detta.

const result: unknown = {
  movieName: "test",
};

if (
  typeof result === "object" &&
  result !== null &&
  "movieName" in result &&
  typeof result.movieName === "string" // <-- Error Here
) {}

Felet anger

Egenskapen 'movieName' finns inte på typen 'object'

Hur begränsar jag det så att det vet att unknown-saken är ett object som innehåller egenskapen movieName? Hur får jag åtkomst till result.movieName för en unknown-typ?

redigera: kanske är det inte möjligt? och rekommendationen i kommentarerna nedan att deklarera det som en Record kan vara det enda sättet enligt denna GitHub-förfrågan?

Svar #1

UPPDATERING FÖR TS4.9+

TypeScript 4.9 kommer att introducera stöd för in-operatorns avsmalning för olistade egenskaper, som implementerat i microsoft/TypeScript#50666, som en lösning för microsoft/TypeScript#21732 nämnt nedan. Vid den tidpunkten kommer ovanstående kod att fungera utan ändring:

const result: unknown = {
    movieName: "test",
};

if (
    typeof result === "object" &&
    result !== null &&
    "movieName" in result &&
    typeof result.movieName === "string" // <-- okay
) {
    result.movieName.toUpperCase(); // <-- okay
}

Playground-länk till kod


TIDIGARE SVAR FÖR TS4.8-

Detta är för närvarande en saknad funktion i TypeScript. Se microsoft/TypeScript#21732 för motsvarande funktionsförfrågan. Just nu, när du använder in-operatorn som en typkontroll som k in result, gör den egentligen bara någon meningsfull avgränsning om typen av result är en union där vissa medlemmar är kända för att ha nyckeln k och andra inte har det. Den försäkrar inte existensen av en egenskap med nyckeln k. Så i ditt fall, där typen av result bara är object (avgränsad från unknown), händer ingenting meningsfullt.

Den lösning jag ibland använder är att skriva min egen användardefinierade typvaktfunktion som beter sig på det sätt jag vill att in ska bete sig. Till exempel:

function hasKey<K extends string, T extends object>(
    k: K, o: T
): o is T & Record<K, unknown> {
    return k in o;
}

Nu, istället för att skriva k in result, skriver jag hasKey(k, result):

if (
    typeof result === "object" &&
    result !== null &&
    hasKey("movieName", result) &&
    typeof result.movieName === "string" // okay
) {
    result.movieName.toUpperCase(); // okay
}

Det här fungerar som du vill, och är antagligen det närmaste man kan komma typ-säkerhet här, åtminstone tills något görs för att ta itu med microsoft/TypeScript#21732 på ett infött sätt.

Lekplatslänk till kod

Relaterade artiklar