亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

[FE] TypeScript關于對象字面量的屬性檢查

標簽:
Java

1. 背景

1.1 子类型

在类型理论中,子类型关系通过S <: T来表示,它表示ST的一个子类型。
子类型关系具有以下两个性质,

(1)自反性

S <: S

(2)传递性

S <: U    U <: T
----------------
     S <: T

对于记录类型来说,
假设有类型S = { a:A, b:B, c:C, ...}T = { x:X, y:Y, z:Z, ... }
S <: T,当且仅当,S包含的字段数多于T

这看上去有些不可思议,包含字段更多的类型S,反而“更小”,
这种性质被称为,广度子类型化(width subtyping rule)。

1.2 和类型

和类型是一种带标签的联合类型(tagged union),
通过给各分量增加标签,将它们放在了一起。

类型A与类型B的和类型,通常记为A + B,例如,

Addr = PhysicalAddr + VirtualAddr

通常通过类型标记,来区分Addr的不同分量,
例如,如果pa是一个PhysicalAddr,则inl pa是一个Addr
其中,inlinr可以看做是一个函数

inl : PysicalAddr -> PhysicalAddr + VirtualAddr
inr : VirtualAddr -> PhysicalAddr + VirtualAddr

一般的,一个类型A + B的元素,
是由标记为inlA元素,和标记为inrB元素组成的。

和类型相关的类型推导规则如下,

    a: A
------------
inl a: A + B
    b: A
------------
inr b: A + B

2. TypeScript

TypeScript中的interface和union types,
分别对应于上文提到的记录类型,与和类型

(1)记录类型
根据记录类型的广度子类型化规则,以下子类型关系成立,

{a:number, b:number} <: {a:number}
{a:number, b:number} <: {b:number}

即,包含更多字段的{a:number, b:number},具有“更小”的类型。

(2)和类型
又根据,和类型的推导规则,

 x: {a:number, b:number} 
--------------------------
x: {a:number} | {b:number}

即,如果x是类型为{a:number, b:number}的值,则它也是类型为{a:number} | {b:number}的值。

3. 问题

但实际上,以上的写法是有问题的,

type A = { a: number };type B = { b: number };type AB = A | B;

// Type '{ a: number; b: number; }' is not assignable to type 'A'.
// Object literal may only specify known properties, and 'b' does not exist in type 'A'.
const x: A = { a: 1, b: 1 };function f(p: A) { }

// Argument of type '{ a: number; b: number; }' is not assignable to parameter of type 'A'.
// Object literal may only specify known properties, and 'b' does not exist in type 'A'.
f({ a: 1, b: 1 });

TypeScript这样的做法,容易使人造成困扰

因为,这样看起来,{a: number, b: number}不是{a: number}的子类型,
也不是{b: number}的子类型。

然而,如果不是子类型的话,为什么{a: number, b: number}类型的值,
可以安全的赋值给{a: number} | {b: number}呢?

const y: AB = { a: 1, b: 1 };  // OK !

TypeScript会出现这样的问题,其实源于它除了进行类型检查之外,
针对对象字面量还多做了一些检查,官网记为,Excess Property Checks

Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the “target type” doesn’t have, you’ll get an error.

注:

(1)不采用对象字面量(Object literals)的写法是完全没有问题的

type A = { a: number };
type B = { b: number };
type AB = A | B;const t = { a: 1, b: 1 };const x: A = t;  // OK !function f(p: A) { }
f(t);  // OK !

(2)在对象字面量后面使用as指定类型,就不会报错了

type A = { a: number };
type B = { b: number };
type AB = A | B;const x: A = { a: 1, b: 1 } as A;  // OK !function f(p: A) { }
f({ a: 1, b: 1 } as A);  // OK !

(3)字面量属性检查,会检查是否传入了过多的属性字段,我们看3个字段的情形

type A = { a: number };type B = { b: number };type AB = A | B;

// Type '{ a: number; b: number; c: number; }' is not assignable to type 'AB'.
// Object literal may only specify known properties, and 'c' does not exist in type 'AB'.
const x: AB = { a: 1, b: 1, c: 1 };function f(p: A) { }

// Argument of type '{ a: number; b: number; c: number; }' is not assignable to parameter of type 'A'.
// Object literal may only specify known properties, and 'b' does not exist in type 'A'.
f({ a: 1, b: 1, c: 1 });



作者:何幻
链接:https://www.jianshu.com/p/c9c818be48ea


點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消