[英]Typescript: Narrowing down mapped types does not work with generics
[英]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 中,除了null
和undefined
之外的每個值都可以分配給所謂的空對象類型{}
。 因此,您可以將您的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)
會自動將o
從unknown
縮小到{}
:
// TS4.8+
function nowNarrowing(o: unknown) { // okay
if (o !== null && o !== undefined) {
console.log(o.toString(), o.constructor);
}
}
@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 中, 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.