基础类型
let isDone: boolean = true // 布尔值
let decLiteral: number = 20 // 数字
let hexLiteral: number = 0x14
let binaryLiteral: number = 0b10100
let octalLiteral: number = 0o24 //8进制
let name: string = 'Jack' //字符串
let sentence: string = `Hello ${name}`
let list: number[] = [1, 2, 3] // 数组
let list2: Array<number> = [4, 5, 6]
let x: [string, number] // 元组 Tuple
x = ['hello', 2]
x[2] = 3 // 越界元素为联合类型,既可以是string也可以是number 最新版越界会报错
// 枚举
enum Color {
Red = 1,
Green,
Blue
}
let c: Color = Color.Green
let colorName: string = Color[2] //Green
// any 不做检查,回归JS
let notSure: any
notSure = 'not'
notSure = 3
let list: any[] = [1, true, 'free']
//void 没有任何类型,如函数中不返回任何值
function log(content): void {
console.log(content)
}
// null
// undefined
// never 不存在的类型,是任何类型的子类型
// 场景一
function error(message: string): never {
throw new Error(message)
}
function fail() {
return error('something failed')
}
// 场景二
function inifiniteLoop(): never {
while(true) {}
}
// Object
declare function create(o: object | null): void
create(o: {prop: 0})
create(o: null)
create(o: 1)
create(o: 'string')
//类型断言
let someValue: any = 'this is a string'
let strLength: number = (<string>SomeValue).length
let strLength2: number = (SomeValue as string).length // 强制转化为一种类型
变量声明
var
闭包
function f() {
var a = 10
return function g() {
var b = a + 1
return b
}
}
var g = f()
var result = g()
console.log(result)// 11
let
块级作用域
function f(input: boolean) {
let a = 100
if (input) {
let b = a + 1
return b
}
return b // error
}
- 暂时性死区 声明前不能读写(var 不存在这种现象)
- 不能被重定义(var可以)
const
除非计划要修改,否则一律使用const
const numLiveForCat = 9
const kitty = {
name: 'kitty',
numLives: numLiveForCat
}
kitty.name = 'Jerry'
kitty.numLives--
解构
// 数组解构
let input = [1, 2]
let [first, second] = input
// 等价于
let first = input[0]
let second = input[1]
// 剩余变量
let [first, ...rest] = [1,2,3,4] // rest [2,3,4]
let [,second,,fourth] = [1,2,3,4] // second 2 fourth 4
// 对象解构
let obj = {
a: 'foo',
b: 12,
c: 'bar'
}
let {a, b} = obj // a 'foo' b 12
// 默认值
function keepWholeObject(wholeObject: { a: string, b?: number }) {
let { a, b = 1001 } = wholeObject
}
// 函数声明
function f({a = '', b = 0} = {}): void {}
function f({a, b = 0} = {a: ''}): void {}
展开(扩展)
// 数组展开
let first = [1, 2]
let second = [3, 4]
let bothPlus = [0, ...first, ...second, 5] // [1,2,3,4,5]
// 对象展开
let defaults = {
food: 'spicy',
price: '$10',
ambiance: 'noisy'
}
let search = {...defaults, food: 'rich'} // {food: 'rich', price: '$10', ambiance: 'noisy'}
let search2 = {food: 'rich', ...defaults} // {food: 'spicy', price: '$10', ambiance: 'noisy'}
接口
基本用法
interface LabelledValue {
label: string
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label)
}
let myObj = { size: 10, label: 'Size 10 Object'}
printLabel(myObj) // Size 10 Object
可选属性
// 对可能出现的属性做一个预定义
// 错误提示
interface Square {
color: string
area: number
}
interface SquareConfig {
color?: string
width?: number
}
function createSquare(config: SquareConfig): Square {
let newSquare = {
color: 'white',
area: 100
}
if (config.color) {
newSquare.color = config.color
}
if (config.width) {
newSquare.area = config.width * config.width
}
return newSquare
}
let mySquare = createSquare(config: {color: 'black'})
只读属性
interface Point {
readonly x: number
readonly y: number
}
let p1: Point = {x: 10, y: 20}
Point.x = 5 // error
// 泛型只读数组
let arr: number[] = [1,2,3,4]
let ro: ReadonlyArray<number> = arr
ro[0] = 12 // error
额外属性检查
interface Square {
color: string
area: number
}
interface SquareConfig {
color?: string
width?: number
[propName: string]: any // 额外类型
}
function createSquare(config: SquareConfig): Square {
let newSquare = {
color: 'white',
area: 100
}
if (config.color) {
newSquare.color = config.color
}
if (config.width) {
newSquare.area = config.width * config.width
}
return newSquare
}
let mySquare = createSquare(config: {color: 'black'})
函数类型
interface SearchFunc {
(source: string, subString: string): boolean
}
let mySearch: SearchFunc
mySearch = function(src: string, sub: string): boolean {
let result = src.search(sub)
return result > -1
}
可索引的类型
interface StringArray {
[index: number]: string
}
let myArray: StringArray
myArray = ['Bob', 'Fred']
let myStr: string = myArray[0]
类类型
// 接口只描述类的公共部分,不检查私有部分
interface ClockInterface {
currentTime: Date
setTime(d: Date)
}
class Clock implements ClockInterface {
currentTime: Date
constructor(h: number, m: number) {}
setTime(d: Date) {
this.currentTime = d
}
}
接口继承类
接口继承接口
interface Shape {
color: string
}
interface Square extends Shape {
sideLength: number
}
let square = {} as Square
square.color = 'blue'
square.sideLength = 10
继承多个接口
interface Shape {
color: string
}
interface PenStroke {
penWidth: number
}
interface Square extends Shape, PenStroke {
sideLength: number
}
let square = {} as Square
square.color = 'blue'
square.sideLength = 10
square.penWidth = 20
混合类型
interface Counter {
(start: number): string
interval: number
reset(): void
}
function getCounter(): Counter {
let counter = (function(star: number){
}) as Counter
counter.interval = 123
counter.reset = function() {}
return counter
}
let c = getCounter()
c(10)
接口继承类
class Control {
private state: any
}
interface SelectableControl extends Control {
select()
}
class Button extends Control implements SelectableControl {
select() {}
}
类
基本使用
class Greeter {
greeting: string
constructor(message: string) {
this.greeting = message
}
greet() {
return `Hello ${this.greeting}`
}
}
let greeter = new Greeter('TS')
greeter.greet()
继承后扩展类的方法
// 基类(超类)
class Animal {
move(distance: number = 0) {
console.log(`Animal move ${distance}`)
}
}
// 子类
class Dog extends Animal {
bark() {
console.log('Woof! Woof!')
}
}
const dog = new Dog()
dog.bark()
dog.move(1)
继承并定制父类的方法
// 基类(超类)
class Animal {
name: string
constructor(name: string) {
this.name = name
}
move(distance: number = 0) {
console.log(`${this.name} moved ${distance}m`)
}
}
// 子类
class Snake extends Animal {
constructor(name: string) {
super(name)
}
move(distance: number = 5) {
console.log('Slithering...')
super.move(distance)
}
}
class Hourse extends Animal {
constructor(name: string) {
super(name)
}
move(distance: number = 50) {
console.log('Galloping...')
super.move(distance)
}
}
const sam = new Snake('Sammy')
const tom: Animal = new Hourse('Tommy')
sam.move()
tom.move(24)
公共、私有、修饰符
private
class Animal {
private name: string
constructor(name: string) {
this.name = name
}
move(distance: number = 0) {
console.log(`${this.name} moved ${distance}m`)
}
}
class Rhino extends Animal {
constructor() {
super('Rhino')
}
}
class Employee {
private name: string
constructor(name: string) {
this.name = name
}
}
let animal = new Animal('Goat')
let rhino = new Rhino()
let employee = new Employee('Bob')
animal = rhino
// animal = employee //error
protected 修饰符
class Person {
protected name: string
constructor (name: string) {
this.name = name
}
}
class Employee extends Person {
private department: string
constructor(name: string, department: string) {
super(name)
this.department = department
}
getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}`
}
}
let howard = new Employee('Hpward', 'Sales')
console.log(howard.getElevatorPitch())
// console.log(howard.name) // error
constructor 加protected后只能new他的派生类,即在派生类中才能访问constructor
class Person {
protected name: string
protected constructor (name: string) {
this.name = name
}
}
class Employee extends Person {
private department: string
constructor(name: string, department: string) {
super(name)
this.department = department
}
getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}`
}
}
let howard = new Employee('Hpward', 'Sales')
console.log(howard.getElevatorPitch())
// console.log(howard.name) // error
let john = new Person('John')
readonly 修饰符
class Person {
readonly name: string
constructor (name: string) {
this.name = name
}
}
let john = new Person('John')
// john.name = 'john' // error
参数属性
即给构造函数参数前面加上访问限定符
class Person {
constructor (readonly name: string) {
this.name = name
}
}
let john = new Person('John')
console.log(john.name)
存取器
let psw: string = 'admin'
class Employee {
private _fullName: string
get fullName(): string {
return this._fullName
}
set fullName(newName: string) {
if (psw && psw === 'admin') {
this._fullName = newName
} else {
console.log('Error')
}
}
}
let employee = new Employee()
employee.fullName = 'Bob Smith'
if(employee.fullName) {
console.log(employee.fullName)
}
编译结果
var psw = 'admin';
var Employee = /** @class */ (function () {
function Employee() {
}
Object.defineProperty(Employee.prototype, "fullName", {
get: function () {
return this._fullName;
},
set: function (newName) {
if (psw && psw === 'admin') {
this._fullName = newName;
}
else {
console.log('Error');
}
},
enumerable: true,
configurable: true
});
return Employee;
}());
var employee = new Employee();
employee.fullName = 'Bob Smith';
if (employee.fullName) {
console.log(employee.fullName);
}
静态属性
class Grid {
static origin = {
x: 0,
y: 0
}
scale: number
constructor(scale: number) {
this.scale = scale
}
calculateDistanceFromOrigin(point: {x: number, y: number}) {
let dx = point.x - Grid.origin.x
let dy = point.y - Grid.origin.y
return Math.sqrt(dx * dx + dy * dy) * this.scale
}
}
const g1 = new Grid(1.0)
const g2 = new Grid(5.0)
console.log(g1.calculateDistanceFromOrigin({x:3,y:4}))
console.log(g2.calculateDistanceFromOrigin({x:3,y:4}))
抽象类
abstract class Deparment {
name: string
constructor(name: string) {
this.name = name
}
printName(): void {
console.log(`Department name is ${this.name}`)
}
abstract printMetting(): void
}
class AccoutingDepartment extends Deparment {
constructor() {
super('Accounting ad Auditing')
}
printMetting(): void {
console.log('accounting meeting')
}
generateReports(): void {
console.log('Accounting reports')
}
}
let deparment : AccoutingDepartment
deparment = new AccoutingDepartment()
deparment.printName()
deparment.printMetting()
deparment.generateReports()
补充
修改静态属性
class Greeter {
static standardGreeting = 'Hello ,there '
greeting: string
constructor(message?: string) {
this.greeting = message
}
greet() {
if (this.greeting) {
return `Hello, ${this.greeting}`
} else {
return Greeter.standardGreeting
}
}
}
let greeter: Greeter
greeter = new Greeter('world')
console.log(greeter.greet())
let greeter2: Greeter
greeter2 = new Greeter()
console.log(greeter2.greet())
// 修改静态属性
let greeterMaker: typeof Greeter = Greeter
greeterMaker.standardGreeting = 'Hey there'
let greeter3: Greeter = new greeterMaker()
console.log(greeter3.greet())
函数
基础
// 命名函数
function add(x, y) {
return x + y
}
// 匿名函数
let myAdd = function (x, y) {
return x + y
}
let z = 100
// 使用全局变量
function addToZ(x, y) {
return x + y + z
}
// 函数类型
let myAdd2: (x: number, y: number) => number = function(x: number, y: number): number {
return x + y
}
可选参数
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return `${firstName} ${lastName}`
} else {
return firstName
}
}
let result1 = buildName('Bob')
let result2 = buildName('Bob', 'Adams')
// let result3 = buildName('Bob', 'Adams', 'Sr.') // Expected 1-2 arguments, but got 3.
默认参数
// 注意有默认值的放在后面
function buildName(firstName: string, lastName = 'Smith'): string {
return `${firstName} ${lastName}`
}
let result1 = buildName('Bob')
let result2 = buildName('Bob', 'Adams')
// let result3 = buildName('Bob', 'Adams', 'Sr.') // Expected 1-2 arguments, but got 3.
编译结果
// 注意有默认值的放在后面
function buildName(firstName, lastName): string {
if (lastName === void 0) { lastName = 'Smith'; }
return firstName + " " + lastName;
}
var result1 = buildName('Bob');
var result2 = buildName('Bob', 'Adams');
// let result3 = buildName('Bob', 'Adams', 'Sr.') // Expected 1-2 arguments, but got 3.
剩余参数
// 注意有默认值的放在后面
function buildName(firstName: string, ...restOfName: string[]): string {
return ''
}
let result1 = buildName('Bob')
let result2 = buildName('Bob', 'Adams')
let result3 = buildName('Bob', 'Adams', 'Sr.') // Expected 1-2 arguments, but got 3.
this
let deck = {
suits: ['hearts', 'spades', 'clubs', 'diamonds'],
cards: Array(52),
createCardPicker: function() {
return function() {
let pickedCard = Math.floor(Math.random() * 52)
let pickedSuit = Math.floor(pickedCard / 13)
return {
suits: this.suits[pickedSuit],
card: pickedCard % 13
}
}
}
}
let cardPicker = deck.createCardPicker()
let pickedCard = cardPicker()
console.log(`card:${pickedCard.card},suit:${pickedCard.suits}`)
改用箭头函数
let deck = {
suits: ['hearts', 'spades', 'clubs', 'diamonds'],
cards: Array(52),
createCardPicker: function() {
return () => {
let pickedCard = Math.floor(Math.random() * 52)
let pickedSuit = Math.floor(pickedCard / 13)
return {
suits: this.suits[pickedSuit],
card: pickedCard % 13
}
}
}
}
let cardPicker = deck.createCardPicker()
let pickedCard = cardPicker()
console.log(`card:${pickedCard.card},suit:${pickedCard.suits}`)
明确this的指向
interface Card {
card: number
suit: string
}
interface Deck {
cards: number[]
suits: string[]
createCardPicker(this: Deck) :() => Card
}
let deck: Deck = {
suits: ['hearts', 'spades', 'clubs', 'diamonds'],
cards: Array(52),
createCardPicker: function(this: Deck) {
return () => {
let pickedCard = Math.floor(Math.random() * 52)
let pickedSuit = Math.floor(pickedCard / 13)
return {
suit: this.suits[pickedSuit],
card: pickedCard % 13
}
}
}
}
let cardPicker = deck.createCardPicker()
let pickedCard = cardPicker()
console.log(`card:${pickedCard.card},suit:${pickedCard.suit}`)
this在回调函数中
interface UIElement {
addClickListener(onclick: (this: void, e: Event) => void): void
}
class Handler {
type: string
onClickBad = (e: Event) => {
this.type = e.type
}
}
let h = new Handler()
let uiElemnet : UIElement = {
addClickListener(){}
}
uiElemnet.addClickListener(h.onClickBad)
重载
let suits =['hearts', 'spades', 'clubs', 'diamonds']
function pickCard(x: {suit: string, card: number}[]): number
function pickCard(x: number): {suit: string, card: number}
function pickCard(x): any {
if(Array.isArray(x)) {
let pickCard = Math.floor(Math.random() * x.length)
return pickCard
} else {
let pickedSuit = Math.floor(x / 13)
return {
suit: suits[pickedSuit],
card: x % 13
}
}
}
let myDeck = [
{suit: 'diamonds', card: 2},
{suit: 'spades', card: 10},
{suit: 'hearts', card: 4}
]
let pickCard1 = myDeck[pickCard(myDeck)]
console.log(`crad:${pickCard1.card}, suit:${pickCard1.suit}`)
let pickCard2 = pickCard(15)
console.log(`crad:${pickCard2.card}, suit:${pickCard2.suit}`)
泛型
基础用法
// T 用于捕获用户传递类型,即用户说是啥,当前上下文中以后T就是啥类型
function identity<T>(arg: T): T {
return arg
}
// 使用
// 直接说明
let out1 = identity<string>('str')
// 类型推断
let out2 = identity('str')
function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length)
return arg
}
泛型接口
function identity<T>(arg: T): T {
return arg
}
// 泛型接口
interface GenericIdentityFn<T> {
(arg: T): T
}
// 泛型函数类型
let myIdentity: <T>(arg: T) => T = identity
let myIdentity2: GenericIdentityFn<number> = identity
泛型类
class GenericNumber<T> {
zeroValue: T
add: (x: T, y: T) => T
}
let myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroValue = 0
myGenericNumber.add = function(x, y) {
return x + y
}
let stringNumeric = new GenericNumber<string> ()
stringNumeric.zeroValue = 'Hello '
stringNumeric.add = function (x, y) {
return x + y
}
console.log(myGenericNumber.add(myGenericNumber.zeroValue, 2020))
console.log(stringNumeric.add(stringNumeric.zeroValue, 'world'))
泛型约束
//用接口约束泛型的类型
interface Lengthwise {
length: number
}
//用接口约束泛型的类型
function loggingIdentity<T extends Le>(arg: T): T {
console.log(arg.length)
return arg
}
简单应用
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key]
}
let x = {a:1}
console.log(getProperty(x, 'a'))
// console.log(getProperty(x, 'b')) // error
泛型中使用类类型(工厂函数)
function create<T>(c: {new(): T}): T {
return new c()
}
应用
class BeeKeeper {
hasMask: boolean
}
class LionKeeper {
nametag: string
}
class Animal {
numLengs: number
}
class Bee extends Animal {
keeper: BeeKeeper
}
class Lion extends Animal {
keeper: LionKeeper
}
function createInstance<T extends Animal> (c: new() => T): T {
return new c()
}
createInstance(Lion).keeper.nametag
createInstance(Bee).keeper.hasMask
类型推断
class Animal {
numLegs: number
}
class Bee extends Animal {
}
class Lion extends Animal {
}
// let zoo: Animal[] = [new Bee(), new Lion()] // 自己给出
let zoo = [new Bee(), new Lion()] // 类型推断
上下文类型
class Animal {
numLegs: number
}
class Bee extends Animal {
}
class Lion extends Animal {
}
function createZoo(): Animal[] {
return [new Bee(), new Lion()] // 返回值会根据函数返回值类型推断返回的是Animal数组
}
高级类型
交叉类型
// 多个类型混合为一种类型
function extend<T, U>(first: T, second: U): T&U {
let result = {} as T&U
for(let id in first) {
result[id] = first[id] as any
}
for(let id in second) {
if (!result.hasOwnProperty(id)) {
result[id] = second[id] as any
}
}
return result
}
class Person {
constructor(public name: string) {
}
}
interface Loggable {
log(): void
}
class ConsoleLooger implements Loggable {
log() {}
}
var jim = extend(new Person('jim'), new ConsoleLooger())
jim.name
jim.log()
联合类型
function padLeft(value: string, padding: string | number) {
if (typeof padding === 'number') {
return Array(padding + 1).join(' ') + value
}
if (typeof padding === 'string') {
return padding + value
}
}
padLeft('Hello world', 1)
padLeft('Hello world', ' ')
联合类型使用注意 —— 独有方法的使用
interface Bird {
fly()
layEggs()
}
interface Fish {
swim()
layEggs()
}
function getSmallPet(): Fish | Bird {
//...
}
let pet = getSmallPet()
pet.layEggs()
// pet.swim() // error 使用独有方法会报错
类型保护
用户自定义 is
interface Bird {
fly()
layEggs()
}
interface Fish {
swim()
layEggs()
}
function getSmallPet(): Fish | Bird {
//...
}
let pet = getSmallPet()
pet.layEggs()
// pet.swim() // error 使用独有方法会报错
if (isFish(pet)) {
pet.swim()
} else {
pet.fly()
}
// 类型保护机制 is
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined
}
typeof
instanceof
可以为null的类型
null和undefined既可以为值也可为类型,并且二者都是其他所有类型的有效值
let s = 'foo'
s = null
let sn: string | null = 'bar'
sn = null
sn = undefined
null不能赋值给undefined或者联合类型
function broken(name: string | null): string {
function postfix(epither: string) {
return `${name!.charAt(0)}.the ${epither}`
}
name = name || 'Bob'
return postfix(name)
}
字符串字面量类型
type Easing = 'ease-in' | 'ease-out' | 'ease-in-out'
class UIElemnet {
animate(dx: number, dy: number, easing: Easing) {
if (easing === 'ease-in') {
//...
} else if (easing === 'ease-out') {
} else if (easing === 'ease-in-out') {
} else {
}
}
}
let button = new UIElemnet()
button.animate(0, 0, 'ease-in')