环境搭建:
npm i -g typescript
npm i -g ts-node
报错console
Cannot find name 'console'. Do you need to change your target library? Try changing the 'lib' compiler option to include
解决方式:
npm install -g @types/node
自定义类型:
interface Xiaojiejie {
uname: string,
age: number
}
const xiaohong: Xiaojiejie = {
uname: '小红',
age: 18
}
console.log(xiaohong.age)
ts静态类型分为基础静态类型和对象静态类型
// 基础静态类型
const count: number = 10
const name: string = 'cutaoki'
// 对象类型
// 对象
const Xiaojiejie: {
name: string,
age: number
} = {
name: 'zxy',
age: 20
}
// 数组
const arr: string[] = ['lzp', 'zxy']
// 类/构造函数
class Person{}
const ppl: Person
// 函数
const fn: () => string = () => 'couple' //这里规定必须是一个函数并且返回值必须是字符串
ts在可以自动分析变量类型情况下无需类型注解;但是如果无法分析,则需要使用类型注解
let count = 123
如果函数传入参数为对象,给对象属性添加类型注解要注意写法
function add({num1, num2} : {num1 : number, num2 : number}) {
return num1 + num2
}
const total = add ({num1 : 11, num2 : 12})
函数返回值类型注解
function getTotal(one : number, two : number): number {
return one + two + ''
}
const total = getTotal(1, 2)
在getTotal函数申明时,限制了返回值类型,这样就会报错。需将函数内的 + ' ‘删掉即可
返回类型
void 表示没有任何返回值,即使是空字符串也会报错
never 表示永远不会有值的一种类型(比如抛出异常或根本就不会有返回值的类型或死循环)
any 表示可以是任何类型
数组类型注解
const numArr : number[] = [1, 2, 3]
const strArr : string[] = ['a', 'b', 'c']
const undArr : undefined[] = [undefined, undefined]
const mixArr : (number | string)[] = [1, 'b', 3]
const objArr : {name: string, age: number}[] = [ //也可以用定义好的接口、类型别名或类,形式如:Model1[]
{name: 'taylor', age: 16},
{name: 'crystal', age: 18}
]
//~~~~~~~~~~~~~~~~~~~~~
//type alias 类型别名
//接口与类型别名很相似,区别是类型别名可以直接赋值类型,而接口必须是对象
type Lady = {name: string, age: number}
const objArr : Lady[] = [
{name: 'taylor', age: 16},
{name: 'crystal', age: 18}
]
//~~~~~~~~~~~~~~~~~~~~~
//类
class Madam {
name: string;
age: number;
}
const objArr : Madam[] = [
{name: 'taylor', age: 16},
{name: 'crystal', age: 18}
]
上面如果用类作为数组前类型限制时,会报错Property has no initializer and is not definitely assigned in the constructo如图
错误原因:
在Typescript 2.7 release版本出来后,设置了一个新的编译器选项strictPropertyInitialization。
当本选项 strictPropertyInitialization:true 的时候,编译器会确保一个类中所有的属性都已经初始化,如果没有,那么在属性构建的过程中就会抛出错误。
解决办法(来自https://www.jianshu.com/p/cec1add8ddf0):
//1
class Model1 {
name!: string;
age!: number;
}
const objArr: Model1[] = [
{name: 'taylor', age: 16},
{name: 'crystal', age: 18}
]
//2 在构造器里面为变量赋予一个默认值
class Model1 {
name: string;
age: number;
constructor() {
this.name = '',
this.age = 0
}
}
const objArr: Model1[] = [
{name: 'taylor', age: 16},
{name: 'crystal', age: 18}
]
//3
class Model1 {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name,
this.age = age
}
}
const objArr: Model1[] = [
{name: 'taylor', age: 16},
{name: 'crystal', age: 18}
]
//4
class Model1 {
constructor(public name: string, public age: number) {}
}
const objArr: Model1[] = [
{name: 'taylor', age: 16},
{name: 'crystal', age: 18}
]
元组(类似固定成员类型顺序的数组,完美配合CSV使用)
const tuple: [string, number, string] = ['crystal', 18, 'actor']
元组也可以作为数组的成员类型注解
const tupleArr: [string, number, string][] = [
['crystal', 18, 'actor'],
['taylor', 16, 'singer'],
['yang', 20, 'dancer'],
]
类(与es6的类很相似)
子类中调用父类的属性或方法,在前面加上 super. ,例如父类有个say方法,在子类想调用就要用super.say()
三个关键字:public 默认,允许类的内部和外部使用
private 只允许在类的内部使用
protected 在私有的范围之外还可以在子类中使用,即继承自这个类的子类内部
对于private属性,可以用get和set暴露给类的外部
class Person {
constructor(private _age: number) {}
get getAge() {
return this._age-3
}
set setAge(age: number) {
this._age = age + 5
}
}
const someone = new Person(18)
someone.getAge()
someone.setAge(30)
someone.getAge()
还有一个关键字static,在属性或者方法前面加上static后就是静态属性/静态方法,可以不用创建实例,而通过类点静态属性/静态方法调用。
还有一个关键字readonly,表示只读属性,一旦赋值就没法修改。
class Person {
public readonly _name: string
constructor(name: string) {
this._name = name
}
}
const crystal= new Person('cc')
console.log(crystal._name)
如果子类有构造函数constructor,子类必须调用super方法
class Person {
constructor(public name: string){
}
}
class Teacher extends Person {
constructor(public age: number) {
super('cutaoki') // 如果父类没有constructor函数,就不用传参
}
}
const xiaocang = new Teacher(28)
console.log(xiaocang.name + xiaocang.age)
抽象类
abstract class Girl {
abstract job() //抽象类中的方法必须是抽象方法,而且不需要大括号写具体逻辑
//抽象类的子类必须实现抽象方法
}
calss Crystal extends Girl {
job() {
console.log('action')
}
}
calss Taylor extends Girl {
job() {
console.log('Saw you')
}
}
配置文件——tsconfig.json
在文件根目录下终端使用指令tsc -init,就会生成默认配置文件tsconfig.json
tsc -init
ts-node 指令等于 tsc demo.ts 加 node demo.js
但是ts-node遵循配置文件,tsc demo.ts不会执行默认配置文件
直接执行tsc就会执行默认配置文件
默认会将所有ts文件都转化为js文件,如果按需转化,则可以在配置文件中加入include项,数组中加入要转化的文件名即可,也可以用exclude排除不转化的文件
"include": ["demo.ts", "demo2.ts"]
//"exclude": ["demo3.ts"]
与include共呢个相似的一个项:files,用法也几乎一样
在配置文件的compilerOptions中常用项的功能了解:
"compilerOptions": {
"removeComments": true //删除注释
"strict": true //严格按照ts的书写和语法要求,就是ts的严格模式
"noImplicitAny": true //如果一个变量没有类型注释,则类型推断为any,此项打开后不用再为该变量写类型注释也不会报错。"noImplicitAny"仅在"strict"不生效情况下可以使用
"strictNullChecks": false //如果为true,ts文件中不允许出现null。仅在"strict"不生效情况下可以使用
"outDir": "./build" //指定ts转化生成的js文件的存放位置
"rootDir": "./src" //要转化的ts文件的位置
"sourceMap": true //生成js文件同时生成一个.map文件,里面有生成文件与源文件的一些信息
"noUnusedLocals": true //打开的话如果检测到有未使用的变量则会在打包时报错提示
"noUnusedParameters": true //打开的话如果检测到有未使用的方法则会在打包时报错提示
}
联合类型与类型保护/类型守护
interface Waiter {
anjiao: boolean;
say: () => {}
}
interface Teacher {
anjiao: boolean;
skill: () => {}
}
function judgeWho(a: Waiter | Teacher) {
//传入参数是多种就是联合类型
//因为不确定a是否有say方法,直接执行a.say()会报错
//方法一:断言
if(a.anjiao) {
(a as Teacher).skill()
} else {
(a as Waiter).say()
}
}
function judgeWho2(a: Waiter | Teacher) {
//方法二
if('skill' in a) {
a.skill()
} else {
a.say()
}
}
//方法三
function add(a: number | string, b: number | string) {
if(typeof a === 'number' && typeof b === 'number') {
return `${a}${b}`
}
return 0
}
//方法四
class numObj {
count: number
}
//instance只能用在类上,不然会报错
function addObj(a: object | numObj, b: object | numObj){
if(a instanceof numObj && b instanceof numObj) {
return a.count + b.count
}
return 0
}
枚举
enum Status {
a,
b,
c
}
//枚举默认给成员从0开始排序
console.log(Status.a) //0
console.log(Status.b) //1
console.log(Status.c) //2
//也可以反向查询
console.log(Status[1]) //b
//枚举可以自定义排序起始编号
enum Status {
a = 5,
b,
c
}
console.log(Status.a) //5
console.log(Status.b) //6
console.log(Status.c) //7
泛型
//泛型在真正使用时才确定其类型
function join<T>(a: T, b:T) {
return `${a}${b}`
}
join<number>(1, 2)
//泛型中数组的使用
function myFun<T>(params: T[]) { //还有一种写法:function myFun<T>(params: Array<T>)
return params;
}
myFun<string>(['abc', '123'])
//多个泛型的使用情况
function join<T, P>(a: T, b: P) {
return `${a}${b}`
}
join<string, number>('abc', 123)
//泛型支持类型推断,所以这里也可以写成join('abc', 123)
//泛型的类型推断不利于代码理解,不建议使用
类中使用泛型
class SelectMark<T extends number | string> { //泛型约束,泛型的类型只能是二者之一
constructor(private marks: T[]) {}
getMark(index: number): T {
return this.marks[index]
}
}
const selectMakr = new SelectMark<string>(['a','b','c'])
console.log(selsecMark.getMark(1))
泛型的继承
interface Mark {
name: string
}
class SelectMark<T extends Mark> {
constructor(private marks: T[]) {}
getMark(index: number): string {
return this.marks[index].name
}
}
const selectMark = new SelectMark([
{name: 'taylor'},
{name: 'crystal'},
{name: 'cutaoki'}
])
console.log(selectMark.getMark(1))
命名空间,减少全局变量污染,实现基本的封装
namespace Home{
class Header {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Header'
document.body.appendChild(elem)
}
}
class Content {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Content'
document.body.appendChild(elem)
}
}
class Footer {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'This is Footer'
document.body.appendChild(elem)
}
}
export class page{
constructor() {
new Header()
new Content()
new Footer()
}
}
}
子命名空间
namespace Components{
export namespace SubComponents{
export class Test{}
}
}