[英]Narrowing down to common JS methods and properties in TypeScript
Is there a way to make this TypeScript narrowing less ugly (or more elegant ;-) ❓有没有办法让这个 TypeScript 缩小不那么难看(或更优雅;-) ❓
With IsSomething
type guard, I want to narrow down access to common methods and properties of any JavaScript variable which is not null
and not undefined
(things like .toString
, .valueOf
, .hasOwnProperty
, .constructor
etc.)使用
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);
}
}
In TypeScript, every value except for null
and undefined
is assignable to the so-called empty object type {}
.在 TypeScript 中,除了
null
和undefined
之外的每个值都可以分配给所谓的空对象类型{}
。 So you can simplify your Something
to just {}
and your user-defined type guard function will work the same as before:因此,您可以将您的
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);
}
}
Furthermore, TypeScript 4.8 will introduce improved support for narrowing unknown
, after which your "NotNarrowing" function will start working, because checking (o !== null && o !== undefined)
will narrow o
from unknown
to {}
automatically:此外,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's excellent answer led me to the following solution: @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);
}
}
It turns out, TypeScript has a predefined interface Object
, which works exactly the way I want:事实证明,TypeScript 有一个预定义的
interface Object
,它完全按照我想要的方式工作:
In TypeScript, the Object
interface is different from the primitive object
type, as the former is still assignable to any other primitive or complex type.在 TypeScript 中,
Object
接口不同于原始object
类型,因为前者仍然可以分配给任何其他原始或复杂类型。 It is also different from an empty type like type Something = {}
, as the latter doesn't supports IntelliSense.它也不同于
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;
One subtle issue still remains.一个微妙的问题仍然存在。 As @CertainPerformance pointed out , the above won't work for an edge case like
Object.create(null)
, where an object is created which doesn't have any properties or methods, but isn't null
either.正如@CertainPerformance 指出的那样,上述方法不适用于像
Object.create(null)
这样的边缘情况,其中创建的对象没有任何属性或方法,但也不为null
。
If that's a requirement, the following should do the job:如果这是一项要求,则应执行以下操作:
// 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.