TypeScript ``` Narrow number literal types with comparison ```

uqzxnwby  于 6个月前  发布在  TypeScript
关注(0)|答案(2)|浏览(44)

搜索词

常量数字字面量缩小比较

建议

不仅使用(非)相等性来缩小数字字面量类型,还要使用小于等。
此请求仅涉及丢弃不匹配的字面量,而不是全面的 number 缩小。

用例

这可以用于指导元组联合的缩小。

示例

带字面量的:

type X = 0 | 1 | 2 | 3;
function f(): X {
    return 1;
}
function g(x: 0 | 3) { 
    console.log(x);
}
let x: X = f();
g(x); // Error, 1 | 2 is unexpected
if (x > 2) { 
    g(x); // Same error, but should be safe
}
if (x != 1 && x != 2) { 
    g(x); // Ok
}

带元组的:

type X = [] | [string, string];
function f(): X { return [];}
function g(x: string) { 
    console.log(x);
}
let x: X = f();
g(x[0]); // Error, undefined is unexpected
if (x.length > 0) { 
    g(x[0]); // Error, but should be ok
}
if (x.length == 2) { 
    g(x[0]); // Ok
}

检查清单

我的建议满足以下准则:

  • 这不会对现有的 TypeScript/JavaScript 代码造成破坏性的更改
  • 这不会改变现有 JavaScript 代码的运行时行为
  • 这可以在不根据表达式的类型发出不同的 JS 的情况下实现
  • 这不是一个运行时特性(例如库功能、带有 JavaScript 输出的非 ECMAScript 语法等)
  • 这个特性将与 TypeScript's Design Goals 的其他部分保持一致。
vq8itlhq

vq8itlhq1#

我们有一个Azure SDK团队的用例,类似于这样。我们正在开发为每个状态码提供响应类型的客户端,其中状态码是区分符。
考虑以下定义:

interface Item {
  name: string;
  price: number;
}

declare function getItem(id: string):
  | { code: 200, body: Item }
  | { code: 404, body: NotFoundError }
  | { code: 500, body: InternalServerError }

我们看到用户尝试使用此代码如下:

const item = getItem(id);

if (item.code >= 400) {
  throw new Error("😣");
}

console.log(item.body.price); // error here

不幸的是,narrowing只能与等于比较一起使用。其他比较运算符没有期望的效果。
/cc @DanielRosenwasser, @SeaRyanC

rta7y2nd

rta7y2nd2#

重用了一些示例来生成测试用例:

// @strict: true

// @filename: basicLiterals.ts

export type Nums = 0 | 1 | 2 | 3;

export declare function f(x: 1 | 2): void;
export declare function g(x: 0 | 3): void;
export declare let x: Nums;

// Should error - '0 | 3' is not assignable
f(x)

// Should error - '1 | 2' is not assignable
g(x);

if (0 < x && x < 3) {
    // Should work.
    f(x);

    // Should error - '1 | 2' is not assignable
    g(x);
}
if (x < 0 || x ) {
    // Should error - '0 | 3' is not assignable
    f(x);

    // Should work.
    g(x);
}

// @filename: statusCodes.ts
export interface Item {
    name: string;
    price: number;
}
export interface NotFoundError {
    isNotFound: true;
}
export interface InternalServerError {
    isServerError: true;
}

export declare function getItem(id: string):
    | { code: 200, body: Item }
    | { code: 404, body: NotFoundError }
    | { code: 500, body: InternalServerError }

const item = getItem("some-id");

if (item.code >= 400) {
    throw new Error("oh no");
}

console.log(item.body.price);

// @filename: tuples.ts

export type Tup = [] | [string, string];
export declare function printString(str: string): void;
declare const tup: Tup;

// Should error
printString(tup[0]);
if (tup.length > 0) {
    // Should work.
    printString(tup[0]);
}

相关问题