深入浅出typescript
在Youtube上看视频学了一下typescript,主要为了接下来读源码方便。
primitive类型的用小写。少用object/any。可以直接用[key: string]
这样的方式去定义规范。
interface Person {
readonly sex: string;
[key: string] : string | number;
}
const a: Person = {
sex: 'man',
name: 'as',
foo: 2
}
class 语法, implements与extends
interface Person {
name: string;
address?: string;
sayHi: Function
}
class Patient implements Person {
name: string;
address?: string | undefined;
constructor ( name: string, addressCode?: number) {
this.name = name
this.address = 'nation:' + (addressCode || 'empty')
}
sayHi = () => {
console.log(this.name + ' say hey')
}
}
class BadPatient extends Patient {
age: number
constructor ( name:string, age:number, addressCode?:number ) {
super(name, addressCode)
this.age = age
}
sayHi = () => {
console.log(this.name + ' is ' + this.age)
}
}
const xiaoMing = new BadPatient( 'xiaoming',23, 32 )
console.log(xiaoMing)
class Greeter<A> {
private greeting: A
constructor ( message: A ) {
this.greeting = message
}
public greet() {
console.log(`hello ${this.greeting}`)
}
}
const a = new Greeter<string>( 'miya' )
对函数也可以定义多个type。
interface add {
( a: number, b: number ): number
}
interface add {
( a: string, b: string ): string
}
const addFunc: add = ( s: any, d: any ) => s + d
console.log(addFunc( '2', '32' ))
console.log(addFunc(2, 32))
扩展类型
interface Lengthwise {
length: number,
0: number
}
function loggingIdentity<T extends Lengthwise>( arg: T ): T {
console.log( arg.length, arg[ 0 ].toExponential() )
return arg
}
loggingIdentity([9.234])
module可以在tsconfig里配,正常import export即可。node8之后实验性地支持es6。
node --experimental-modules bar.mjs
namespace编译后其实就是一个object。类似沙箱。处理冲突。
namespace lala {
function foo( a: string ): number {
return a.length
}
let name:string = 'sdsd'
}
// 编译后:
(function (lala) {
function foo(a) {
return a.length;
}
var name = 'sdsd';
})(lala || (lala = {}));
decorators,多用于class内的方法或属性。也可以用于整个class
function log( target: any, key: any, descriptor: any ) {
const original = descriptor.value
if ( typeof original === 'function' ) {
descriptor.value = function () {
const result = original.apply( this, arguments )
console.log( {result})
}
}
return descriptor
}
class Foo {
@log
greet( a: void ): string {
return 'hello'
}
}
const b = new Foo()
b.greet()
// T has to be in construtor form so the fucntion know how to extends it
function init<T extends { new( ...args: any[] ): {} }>( constructor: T ): T {
return class extends constructor {
firstName = 'mengge'
lastName = 'xue'
}
}
@init
class Coder{
firstName: string = ''
lastName: string = ''
}
const a = new Coder()
console.log(a.firstName, a.lastName, a instanceof Coder)
mixins
class Swimer {
speed = 10
swim( distance: number ): number {
return distance * this.speed
}
}
class Runner {
speed = 10
run( distance: number ): number {
console.log(distance, this.speed, '---')
return distance * this.speed * 10
}
}
class Person implements Swimer, Runner {
speed = 2
swim( distance?:number ) {
return -2
}
run( distance?: number ) {
console.log(distance)
return 1200
}
}
function applyMixins( derivedCtor: any, baseCtors: any[] ) {
baseCtors.forEach( baseCtor => {
Object.getOwnPropertyNames( baseCtor.prototype ).forEach( name => {
derivedCtor.prototype[ name ] = baseCtor.prototype[ name ]
} )
} )
}
applyMixins( Person, [ Swimer, Runner ] )
const person = new Person()
console.log(person.run(12), person.speed)
type和type也可以和或并。
interface Person {
name: string
sayHi?: Function
}
interface Animal {
type: string
}
type Kitty = Person & Animal
const cat: Kitty = {
name: 'kemo',
type: 'cat'
}
this type。this也是一种特殊的类型。函数中返回this,可以用于链式函数。
class BasicCalculator {
// 这里加上protected之后,constructor里等于写了this.value = value
public constructor ( protected value: number = 0 ) { }
public currentValue(): number {
return this.value
}
public add( operand: number ): this {
this.value += operand
return this
}
public multiply( operand: number ): this {
this.value *= operand
return this
}
}
const c = new BasicCalculator( 2 )
console.log(c.add(20).multiply(3).currentValue())
mapped types 快捷写法,利用已有的type,生成相应的特殊type。在react/angular中很有用
/*
in lib.es5.d.ts
type Readonly = {
readonly [p in keyof T]: T[P]
}
type Partial = {
[P in keyof T]?: T[P]
}
*/
type Person = {
name: string,
age: number
}
type PersonPartial = Partial<Person>
type ReadonlyPerson = Readonly<Person>
const zhenzhen: ReadonlyPerson = {
name: 'zhenzhen',
age: 12
}
// zhenzhen.age = 23 cannot assign to 'age' cause it is readonly
// pick
type Pick<T, K extends keyof T> = { [P in K]: T[P] }
type ColorDuck = Pick<Duck, 'color>
// = {color: string}
async function fetchUserById<T extends keyof Person>(id: string, ...fields: T[]): Promise<Pick<Reaction, T>> {
return await kenx('User').where({id}).select(fields).first()
}
declare function f<T extends boolean>( x: T ): T extends true ? string : number
let x = f(Math.random() < 0.5)
type StringOrNumber<T> = T extends boolean? string : number
type T1 = StringOrNumber<true> // string
type T2 = StringOrNumber<object> //number
type ElementType = T extends (infer U)[]? U: never
type T = ElementType<[]> // never
type T1 = ElementType // string