簡體   English   中英

縮小到 TypeScript 中常見的 JS 方法和屬性

[英]Narrowing down to common JS methods and properties in TypeScript

有沒有辦法讓這個 TypeScript 縮小不那么難看(或更優雅;-) ❓

使用IsSomething類型保護,我想縮小對任何null且未undefined的 JavaScript 變量(如.toString.valueOf.hasOwnProperty.constructor等)的常用方法和屬性的訪問范圍

游樂場鏈接

export type Something = 
  number | string | boolean | symbol | object | bigint;

export function IsSomething(value: unknown) : value is Something {
  return value !== undefined && value !== null;
}

let a = [1, "2", 3];
Narrowing(a);
NotNarrowing(a);

function Narrowing(o: unknown) { // OK
    if (IsSomething(o)) {
      console.log(o.toString(), o.constructor);
    }
}

function NotNarrowing(o: unknown) { // NOT OK
    if (o !== null && o !== undefined) {
      console.log(o.toString(), o.constructor);
    }
}

在 TypeScript 中,除了nullundefined之外的每個值都可以分配給所謂的空對象類型{} 因此,您可以將您的Something簡化為{} ,並且您的用戶定義類型保護函數將像以前一樣工作:

export type Something = {};
function isSomething(value: unknown): value is Something {
  return value !== undefined && value !== null;
}
function narrowing(o: unknown) { // OK
  if (isSomething(o)) {
    console.log(o.toString(), o.constructor);
  }
}

此外,TypeScript 4.8 將改進對縮小unknown的支持,之后您的“NotNarrowing”函數將開始工作,因為檢查(o !== null && o !== undefined)會自動將ounknown縮小到{}

// TS4.8+ 
function nowNarrowing(o: unknown) { // okay
  if (o !== null && o !== undefined) {
    console.log(o.toString(), o.constructor);
  }
}

Playground 代碼鏈接

@jcalz 的出色回答使我找到了以下解決方案:

// With `IsSomething` type guard, I want to narrow down access 
// to common properties of any JS variable 
// which is not null and not undefined, like: 
// .toString, .valueOf, .hasOwnProperty, .constructor etc.

export function IsSomething(value: unknown) : value is Object {  
  return value !== null && value !== undefined;
}

Narrowing([1, 2, 3]);

function Narrowing(o: unknown) { // OK
    if (IsSomething(o)) {
      console.log(o.toString(), o.constructor);
    }
}

事實證明,TypeScript 有一個預定義的interface Object ,它完全按照我想要的方式工作:

TypeScript 中的對象接口

在 TypeScript 中, Object接口不同於原始object類型,因為前者仍然可以分配給任何其他原始或復雜類型。 它也不同於type Something = {}之類的空類型,因為后者不支持 IntelliSense。

// Object interface is OK
let a: Object = 42; 
let b: Object = true;
let c: Object = "string";
let d: Object = Symbol(42);
let e: Object = new class SomeClass { someProp = 42 };

// Empty type is OK but no IntelliSense 
let a1: {} = 42; 

// Error: Type 'number' is not assignable to type 'object'
let a2: object = 42; 

游樂場鏈接

一個微妙的問題仍然存在。 正如@CertainPerformance 指出的那樣,上述方法不適用於像Object.create(null)這樣的邊緣情況,其中創建的對象沒有任何屬性或方法,但也不為null

如果這是一項要求,則應執行以下操作:

// can be extended to check for toString, valueOf, etc
export function IsSomething(value: unknown) : value is Object {
  return (<Object>value)?.constructor !== undefined;
}

Narrowing([1, 2, 3]);

function Narrowing(o: unknown) { // OK
  if (IsSomething(o)) {
    console.log(o.toString(), o.constructor);
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM