Användning av nyckelordet never i TypeScript


TS-dokumentation säger:

typen never representerar typen av värden som aldrig förekommer. Variabler får också typen never när de begränsas av typer som aldrig kan vara sanna.

Jag förstod inte dess användning, kan någon ge mig ett svar med några exempel.

Svar #1

  1. "typen never representerar typen av värden som aldrig förekommer."

Det kan vara returtypen för en funktion som aldrig returnerar:

const reportError = function () {
    throw Error('my error');
}

const loop = function () {
    while(true) {}
}

Här är både reportError och loop-typen () => never.

  1. "Variabler får också typen never när de begränsas av vilken typvakt som helst som aldrig kan vara sann"

Med operatorer som typeof, instanceof eller in kan vi begränsa variabeltypen. Vi kan begränsa typen på ett sätt så att vi är säkra på att denna variabel på vissa ställen aldrig förekommer.

function format(value: string | number) {
    if (typeof value === 'string') {
        return value.trim();
    } else {
        return value.toFixed(2); // we're sure it's number
    }

    // not a string or number
    // "value" can't occur here, so it's type "never"
}
  1. Vanligt användningsfall

Förutom bättre typkontroll (som i fallen beskrivna ovan), har never-typen ett annat användningsområde - villkorliga typer. Med never-typen kan vi utesluta vissa oönskade typer:

type NonNullable<T> = T extends null | undefined ? never : T;

type A = NonNullable<boolean>;            // boolean
type B = NonNullable<number | null>;      // number

Svar #2

En tidigare version av Typescript-dokumentationen för never hade flera exempel:

// Function returning never must have unreachable end point
function error(message: string): never {
    throw new Error(message);
}

// Inferred return type is never
function fail() {
    return error("Something failed");
}

// Function returning never must have unreachable end point
function infiniteLoop(): never {
    while (true) {
    }
}

Svar #3

typen never representerar typen av värden som aldrig förekommer:

Typescript-kompilatorn tilldelar typer till alla dina variabler/egenskaper. Dessa typer kan antingen vara de typer som definieras av Typescript som number och string, eller användardefinierade typer skapade med nyckelorden interface och type.

Det är användbart att tänka på dessa typer som mängder. Med andra ord är en typ i sig en samling av möjliga saker som dina variabler/egenskaper kan vara vid den tidpunkten. Till exempel:

// the variable five can be one thing which is a number
const foo = 5; // type = number; 

// bar can be two things
type twoPrimitives = string | number;
let bar: twoPrimitives = 4; 
  • Vi ser att foo har en inställd storlek på 1 >> {number}
  • Vi ser att bar har en inställd storlek på 2 >> {nummer, sträng}

Nu med vår mängddefinition i åtanke kan vi enkelt definiera never-typen:

typen never representerar den tomma typmängden >> {}. det vill säga en mängd med 0 objekt i.

Till exempel:

// Normally a function which do not have a return value returns undefined implicitly
// However this function throws before ever reaching the end. 
// Therefore the return type will be never
function foo() :never {
   throw new Error("Error");
}

// thisMakesNoSense will be type never, a value can never be number and string at the same time
type thisMakesNoSense = number & string; 

Variabler får också typen aldrig när de begränsas av några typvakter som aldrig kan vara sanna.

TS kan kontrollera smala typer om de uttryckligen kontrolleras i if-satser. Detta kallas typvakter. Med andra ord är en typvakt ett uttryck som utför en kontroll vid körning som garanterar typen inom ett visst område. Till exempel:

// The compiler actually screens these if statements and can infer that in the third
// else statement there are no more types left for value to take on and thus the type 
// become never. Another way to think about this is that in the first if statement the
// set of possible types shrinks from string | number to number only.
// Then in the seconds if statement it shrinks from number to never
function typeGuards(
    value: string | number
) {
    if (typeof value === "string") {
        value; // Type string
    } else if (typeof value === "number") {
        value; // Type number
    } else {
        value; // Type never
    }
}

Svar #4

Länkar som jag studerade från: https://www.typescriptlang.org/docs/handbook/basic-types.html https://basarat.gitbooks.io/typescript/docs/types/never.html https://egghead.io/lessons/typescript-use-the-never-type-to-avoid-code-with-dead-ends-using-typescript https://blog.mariusschulz.com/2016/11/18/typescript-2-0-the-never-type

Kan sammanfattas som att typen never används för fall som:

  1. En funktion returnerar aldrig (t.ex. om funktionskroppen har while(true){})

    //Type () => never
    
    const sing = function() {
      while (true) {
        console.log("Never gonna give you up");
        console.log("Never gonna let you down");
        console.log("Never gonna run around and desert you");
        console.log("Never gonna make you cry");
        console.log("Never gonna say goodbye");
        console.log("Never gonna tell a lie and hurt you");
      }
    };
    
  2. En funktion kastar alltid (t.ex. i funktionen foo(){throw new Error('Not Implemented')} är returtypen för foo never)

    // Type (message: string) => never
    const failwith = (message: string) => {
      throw new Error(message);
    };
    

Användningsfall: Utslutande kontroller

function foo(x: string | number): boolean {
  if (typeof x === "string") {
    return true;
  } else if (typeof x === "number") {
    return false;
  }

  // Without a never type we would error :
  // - Not all code paths return a value (strict null checks)
  // - Or Unreachable code detected
  // But because TypeScript understands that `fail` function returns `never`
  // It can allow you to call it as you might be using it for runtime safety / exhaustive checks.
  return fail("Unexhaustive!");
}

function fail(message: string): never { throw new Error(message); }

Relaterade artiklar