likes
comments
collection
share

Typescript tip: freshness(更严格的对象字面量检查)

作者站长头像
站长
· 阅读数 9

Typescript 是结构化的类型系统,那么对于对象来说,如果 A 具有 B 的所有属性,并且属性对应的类型相匹配,那么 A 就能赋值给 B

type A = {
    name:string;
    age:number;
}
type B = {
    name:string
}

declare let a:A
declare let b: B
b = a

但是其中有一个例外的情况,会强制 a、b 具有完全相同的结构,被称为 freshness,也被称为更严格的对象字面量检查

let b: {
    name:string
}

b ={name:'1',age:1}
/* 
  Type '{ name: string; age: number; }' is not assignable to type '{ name: string; }'.
  Object literal may only specify known properties, and 'age' does not exist in type '{ name: string; }'
*/

function freshness({name}:{name:string}){
    return 1
}
freshness({name:'du',age:1}); 
/*
  Argument of type '{ name: string; age: number; }' is not assignable to parameter of type '{ name: string; }'.
  Object literal may only specify known properties, and 'age' does not exist in type '{ name: string; }'
*/

play

之所以有这样的严格检查是因为存在以下两个缺点:

1.结构化类型系统非常方便,但是它可能让你误以为某些函数接收的比他实际需要的多

function logName(something: { name: string }) {
  console.log(something.name);
}

logName({ name: 'matt', job: 'being awesome' })

2.在实现此功能之前 Typescript 并不能很好的检测出对象中的错误,特别是指定可选类型时

interface TextOptions {
    alignment?: string;
    color?: string;
    padding?: number;
}
function drawText(opts: TextOptions) { ... }

// None of these were errors before
drawText({ align: 'center' }); // Oops
drawText({ colour: 'grey' }); // Oops
drawText({ pading: 32}); // Oops

如上例子可能只是拼错了而已,但是在此之前 Typescript 并不能检测出来

具体规则而言

  1. 每个对象字面量都被认为是新鲜的
  2. 当一个新的字面量对象被分配给一个变量或者传递给一个非空的目标类型参数时,如果对象指定了目标类型中不存在的属性,那就是一个错误
  3. 在一个类型断言中,或者当一个对象字面的类型被扩大时,新鲜感就会消失
var x: { foo: number };
x = { foo: 1, baz: 2 };  // Error, excess property `baz`

var y: { foo: number, bar?: number };
y = { foo: 1, baz: 2 };  // Error, excess or misspelled property `baz`

当新鲜类型被捕获到变量中时,不会发生错误

var x: { foo: number };
x1 = { foo: 1, baz: 2 };
x = x1;

var y: { foo: number, bar?: number };
y1 = { foo: 1, baz: 2 };
y = y1;

参考: jkchao.github.io/typescript-…

github.com/microsoft/T…