TypeScript 是由微软开发的自由和开源的编程语言,是 JavaScript 的一个超集,支持 ECMAScript 6 标准。其设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。
目前主流的前端框架(react、vue)都使用ts的语法进行开发,typescript也是JavaScript的超集,相对于JavaScript来说更加严谨,
使用typescript可以编写出更加健壮的前端代码。
typescript无法直接在浏览器中执行,需要编译成JavaScript之后才能执行。
let a = 123;
a = '123'
js不会报错,代码可以正常执行(在JavaScript中变量的类型是动态类型,即变量的类型是可以改变的)
以下代码会报错,因为在typescript中,变量是静态类型,变量的类型不能改变(同时变量所属类型的方法跟随确定,例如定义了变量
为number类型,则该变量就会有number类型的方法和属性),vs-code执行示例:
以下代码不会报错,因为在typescript中,变量是静态类型,变量重新赋值时,变量类型不改变,不会提示错误。vs-code执行示例如下:
let a = 123;
// 完整的typescript写法为
let a:number = 123;
// 对a重新赋值时,只要类型不变,就不会提示错误,例如:
a = 456;
在typescript中希望各个变量、属性以及函数参数都有自己的变量类型
// String 类型
// 一个保存字符串的文本,类型声明为 string。可以发现类型声明可大写也可小写,后文同理。
let str: string = 'abcd';
// Boolen 类型
// boolean是 true 或 false 的值
// 所以 let isBool3: boolean = new Boolean(1) 就会编译报错,因为 new Boolean(1) 生成的是一个 Bool 对象。
let isBool: boolean = false;
// Number 类型
let number: number = 10;
// Any 类型
// any 是默认的类型,其类型的变量允许任何类型的值。
let any: any = 10;
// Void 类型
// JavaScript 没有空值 Void 的概念,在 TypeScirpt 中,可以用 void 表示没有任何返回值的函数。
let sym1 = Symbol();
let sym2 = Symbol("key"); // 可选的字符串key
// 需要注意的是,Symbols是不可改变且唯一的。
let sym2 = Symbol("key"); // 可选的字符串key
let sym3 = Symbol("key");
console.log(sym2 === sym3); // false, symbols是唯一的
// 通过同样的方式生成两个symbol也是不同的,因为symbol是唯一的,因此sym2和sym3无论如何都不会相等
// Symbol 类型
// TypeScript中的Symbol的用法跟JavaScript一致,Symbols是不可改变且唯一的。
function alertName(): void {
console.log('My name is changdong');
}
// Null 和 Undefined
// TypeScript里,undefined和null两者各自有自己的类型分别叫做undefined和null。
// 和void相似,它们的本身的类型用处不是很大。
let u: undefined = undefined;
let n: null = null;
> // 默认情况下null和undefined是所有类型的子类型。 就是说你可以把null和undefined赋值给number类型的变量。
> let num: number;
> num = 1; // 运行正确
> num = undefined; // 运行正确
> num = null; // 运行正确
> // 然而,当你指定了--strictNullChecks标记,null和undefined只能赋值给void和它们各自。这能避免很多常见的问题。
> // 启用 --strictNullChecks
> //(启用strictNullChecks可以在项目中的tsconfig.json中配置{strictNullChecks: true},如下图所示)
> let num: number;
> num = 1; // 运行正确
> num = undefined; // 运行错误
> num = null; // 运行错误
> // 如果想传入一个string或null或undefined,你可以使用联合类型string | null | undefined。
> // 启用 --strictNullChecks
> let num2: number | null | undefined;
> num2 = 1; // 运行正确
> num2 = undefined; // 运行正确
> num2 = null; // 运行正确
// Never 类型
// never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。
// 这意味着声明为 never 类型的变量只能被 never 类型所赋值,在函数中它通常表现为抛出异常或无法执行到终止点(例如无限循环)。
let a: never;
let b: number;
// a = 123; // 运行错误,数字类型不能转为 never 类型
a = (() => { throw new Error('never')})(); // 运行正确,never 类型可以赋值给 never类型
b = (()=>{ throw new Error('exception')})(); // 运行正确,never 类型可以赋值给 数字类型
// 返回值为 never 的函数可以是抛出异常的情况
function error(message: string): never {
throw new Error(message);
}
// 返回值为 never 的函数可以是无法被执行到的终止点的情况
function loop(): never {
while (true) {}
}
// Object 类型
// object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。
// 使用object类型,就可以更好的表示像Object.create这样的API
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
// create(42); // Error
// create("string"); // Error
// create(false); // Error
// create(undefined); // Error
// Array 类型
// 数组是 Array 类型。然而,因为数组是一个集合,我们还需要指定在数组中的元素的类型。
// 我们通过 Array or type[] 语法为数组内的元素指定类型
let arr: number[] = [1, 2, 3, 4, 5];
let arr2: Array<number> = [1, 2, 3, 4, 5];
let arr3: string[] = ['1', '2', '3'];
let arr4: Array<string> = ['1', '2', '3'];
// Tuple 类型
// 元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
// 比如,你可以定义一对值分别为string和number类型的元组。
let x: [string, number];
x = ['hello', 10]; // OK
// x = [10, 'hello']; // Error
// Enums 类型
// 枚举类型用于定义数值集合。
// 列出所有可用值,一个枚举的默认初始值是0。你可以调整一开始的范围,后续的数值比前一个大 1 。
enum People {Student = 3, Teacher, Doctor};
let role1: People = People.Student;
let role2: People = People.Teacher;
let role3: People = People.Doctor;
console.log(role1, role2, role3) // 3 4 5
// 可以自己转换成js代码 之后打印一下People
启用 --strictNullChecks
在ts中,我们可以告诉ts,声明的变量是什么类型,叫做类型注解,例如:
let a:number = 123;
let b:string = 'typescript'
如果没有告诉ts变量的类型,ts会自动判断变量的类型,叫做类型推断(如果ts可以判断变量类型,就不需要额外操纵,
但是如果ts不能判断变量类型,就需要使用类型注解,例如:)
function getResult(a, b) { return a + b;}
const result = getResult(1, 2)
// 上述方法中的a、b、result,ts无法自动推断出其变量类型,就需要手动添加类型注解
在typescript中,我们也可以定义函数的返回值类型(对函数做类型注解),例如:
function getNumber():number{} // 指定函数返回值为number
function getNumber():void{} // 表示没有任何返回值的函数
function getNumber():number|string{} // 指定函数返回值为number或者string
// ... 可以定义多种类型
// 解构类型参数的类型注解
function getNumber({a, b}: {a:number, b:number}){return a + b}
const result = getNumber({a: 1, b: 3}) // ts会自动判断result的类型为number
使用typescript开发过程中,typescipt的类型检测可以提示代码编写过程的一些潜在错误,提升开发效率(在js中,以下代码只有在执行的时候才会提示错误)
使用typescript开发时,代码提示很友好(ts会对传入函数的数据属性进行提示)
interface // 可以声明一个类型(只能表示对象类型)
type // 可以声明一个类型,可以表示对象类型和基本类型
在typescript中能用interface(接口)表示类型的时候就用interface,除此之外也可以使用类型变量(boolean、string等),使用如下:
interface Person {}
type Person = {}
interface Person {
readonly name: string,
age?:number
}
// readonly表示name属性只读,不可修改; ?表示age属性可有可无
typescript中,声明变量形式传递参数时,函数会对参数进行校验,只要符合要求即可,如果传入方法中的是自变量对象时,
就会进行强校验,要求参数必须符合要求
如果传入的自变量参数不符合,可以使用如下写法
interface User {
name: string,
age?:number,
[propName: string]: any
}
// [propName: string]: any 表示字符串类型的key,值可以为任何类型,这样就不会提示错误了
interface声明的接口,Class类可以使用 implements 关键字应用声明的接口,其他声明出来的接口可以使用 extends 关键字继承当前接口
interface还可以定义一个函数的类型接口,如下:
interface SayHello {
(str:string):string
}
// 表示该接口函数接受一个字符串类型的参数,返回一个字符串类型的值,使用如下
const sayHello:SayHello = (str:string) => {return str}
跟JavaScript中一样,可以使用class 关键字声明一个类,类可以继承父类的属性和方法,也可以重写覆盖父类的方法,当我们重写父类的
方法之后需要调用父类的方法是,可以使用 super[父类方法] 的形式获取父类的方法和属性;
// class类的访问类型 public、private、protected
class Info {
name: 'user',
sayHi(){
console.log('Hi')
}
}
// public 允许对象的属性和方法在类的内部和外部被调用
// private 允许对象的属性和方法在类的内部被调用
// protected 允许对象的属性和方法在类的内部和继承的子类中使用 (new 关键字实例化的对象不能访问)
// 特殊:static 声明的属性和方法是挂在类上面,而不是示例上面
如果子类通过extends继承父类的属性和方法时,子类中也使用了constructor构造器,则需要在子类的构造器中使用super()方法,
调用父类的构造器,并将父类构造器需要的参数传递进去,如下:
class Person {
// 传统写法
public name: string;
constructor (name: string){
this.name = name
}
// 简化写法
// constructor (public name: string){}
}
// 实例化操作 (实例化时,构造函数的constructor会在创建的时候被执行)
const person = new Person('w-wang')
console.log(person.name) // w-wang
// 使用extends继承时
class Man extends Person {
constructor (public age: number){
super('w-wang') // 调用父类的构造器,并传入参数
}
}
const man = new Man(18)
console.log(man.age); // 18
console.log(man.name); // w-wang
可以使用private设置私有变量,通过使用setter和getter实现访问和修改私有变量(参考vue),如下:
class Person {
constructor (private _name:string){}
get name(){
return this._name
}
set name(){
this._name = name
}
}
const person = new Person('w-wang')
console.log(person.name); // w-wang 实际访问的是Person的get name方法
person.name = 'wei' // 实际访问的是Person的set name方法
// 附加:如果需要定一个不能修改的属性是,可以使用readonly,例如:public readonly name: string; 表示定义一个公开的只读的name属性
也可以根据类的特性,创建一个只能实例化一次的构造函数
class Demo {
private static instance: Demo;
constructor (){}
static getInstance(){
if(!this.instance){
this.instance = new Demo()
}
return this.instance
}
}
const demo1 = Demo.getInstance()
const demo2 = Demo.getInstance()
// demo1和demo2是相同的
备注:可以使用abstract 定义一个抽象类,定义一下公用的抽象方法,供其他的类继承,如下:
abstract class Area {
abstract getArea():number; // 定义返回值为number类型
}
class Circle extends Area{
getArea(){
rentun 123
}
}
class Square extends Area{
getArea(){
rentun 456
}
}
// 其他的类
typescript基础语法学习结束,继续学习