undefined的含义是:一个变量没有初始化。 null的含义是:一个变量的值是空。
要避免这个问题,我们需要做到:
{
"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的值来自于指定的类。
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}
的主要功能是让通用方法可以创建通用类型的对象。
但是,这个故事有点长。
// 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);
// 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(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("Kate", Person);
console.log(person);
```
{new(): T}
的类型是一个 Type,因此可以用于定义变量和参数。
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' }