undefined的含義是:一個變量沒有初始化。
null的含義是:一個變量的值是空。html
要避免這個問題,咱們須要作到:git
用undefined,不要用null。
根據Code guidelines from Microsoft。github
Enable "strict" 或者 "strictNullChecks" 編譯選項
在tsconfig.js中:typescript
{ "compilerOptions": { "strict": true, //... } }
var name: string; // cannot be null and undefined. name = undefined; // Error: [ts] Type 'undefined' is not assignable to type 'string'. name = null; // Error: [ts] Type 'null' is not assignable to type 'string'. console.log(name); // Error: [ts] Variable 'address' is used before being assigned.
var address: string | undefined; // can be undefined class Person { name: string; // cannot be null and undefined address?: string; // can be undefined } var person : Person = {name: "Joe"}; console.log(person.address.toString()); // Error: [ts] Object is possibly 'undefined'. if (person.address != undefined) { console.log(person.address.toString()); //Ok. as we checked the type }
keyof 定義了一個Type, 這個Type的值來自於指定的類。json
class Person { id: number; name: string; birthday: Date; } type personPropKeys = keyof Person; // same as: type personPropKeys = "id" | "name" | "birthday" var propKey : personPropKeys; propKey = "id"; // OK propKey = "name"; // OK propKey = "age"; // Error: [ts] Type '"age"' is not assignable to type '"id" | "name" | "birthday"'.
// Keep types the same, but make each property to be read-only. type Readonly<T> = { readonly [P in keyof T]: T[P]; }; // Same property names, but make the value a promise instead of a concrete one type Deferred<T> = { [P in keyof T]: Promise<T[P]>; }; // Wrap proxies around properties of T type Proxify<T> = { [P in keyof T]: { get(): T[P]; set(v: T[P]): void } };
class Person { // same as to define instance fields: id, name, age constructor(private id: number, public name: string, readonly age: number) { } get Id() : number { return this.id; } } var person = new Person(1, "Mary", 14); console.log(person.name);
{new(): T}
的主要功能是讓通用方法能夠建立通用類型的對象。promise
可是,這個故事有點長。app
// This is a generic method to create an object function createObject<T>(name:string, creator: (arg: string) => T) : T { return creator(name); } // now we have a class Person, we want to create it via function createObject class Person { public constructor(name: string) { this.name = name; } name: string; } // we have to define a creator function function createPerson(name: string): Person { return new Person(name); } // at end, we can create a person var person = createObject<Person>("Kate", createPerson);
實現方法2:使用構造方法。可是行不通。
可是,對象的建立者的主角是構造對象constructor。
專門定義一個creator方法也很彆扭。
咱們但願寫成的代碼是這樣的,可是有一個編譯錯誤。ide
沒有研究過爲何這樣寫行不通。多是在轉義js上有一些問題。函數
// This is a generic method to create an object function createObject<T>(name:string) : T { return new T(name); // Error: [ts] 'T' only refers to a type, but is being used as a value here. } // now we have a class Person, we want to create it via function createObject class Person { public constructor(name: string) { this.name = name; } name: string; } // at end, we can create a person var person = createObject<Person>("Kate");
// This is a generic method to create an object function createObject<T>(name:string, creator: {new(name: string): T}) : T { return new creator(name); } // now we have a class Person, we want to create it via function createObject class Person { public constructor(name: string) { this.name = name; } name: string; } // at end, we can create a person var person = createObject<Person>("Kate", Person); console.log(person);
{new(): T}
的類型是一個 Type,所以能夠用於定義變量和參數。ui
new()
是描述構造函數的簽名。因此在new()
中,也定義參數。好比:{new(name: string): T}
。
{new(): T}
定義了一個返回類型爲 T 的構造函數的Type。
type NewObject<T> = {new(name: string): T}; // type NewPersonType = new (name: string) => Person var newPersonType: NewObject<Person> = Person; var person2 = new newPersonType("Joe"); // we also can write like this, as {} is the root class of object type. type ObjectEmpty = {new(): {}}; // type ObjectEmpty = new () => {}
function restFunction(first: string, second: string, ...args: string[]): void { console.log(args); // [ 'three', 'four' ] } restFunction("one", "two", "three", "four");
// shadow copy var objCopy: any = {...obj}; console.log(objCopy); // { x: 1, y: 'name', z: 2 } console.log(objCopy === obj); // false // copy and change var obj2 = {a: "age"}; objCopy = {...obj, z: "zoo"}; console.log(objCopy); // { x: 1, y: 'name', z: 'zoo' } // merge var obj2 = {a: "age"}; objCopy = {...obj, ...obj2}; console.log(objCopy); // { x: 1, y: 'name', z: 2, a: 'age' } // copy and remove let {z, ...objCopy2} = obj console.log(objCopy2); // { x: 1, y: 'name' }