【TS学习笔记】TypeScript入门学习笔记

1. 数据类型与推断

TypeScript 在声明变量或是函数时需要添加约束也叫类型注释。
支持的基本类型和引用类型有:string、number、boolean、null、undefined、symbol、array、object、Function、any,空值可以使用void来表示,void可以表示变量,也可以表示函数的返回值。
声明数据类型:

let hello:string = 'hello word';
hello = 20; // 报错

类型推断:
通过负值类推断变量的类型

let num = 20;
num = '20'; // 报错,原因时num开始赋值的时数值类型,这他就只能是数值类型

注意:开发过程中必须要类型声明

1.1 编译ts文件

方式一:
tsc 1-helloword.ts
方式二:
全局安装ts-node插件
npm install -g ts-node
安装完成之后,通过命令运行ts文件
ts-node 1-helloword.ts

2. 接口与联合类型

联合类型表示取可以为多种类型中的一种,可以通过管道(|)将变量设置为多种类型,赋值时可以根据设置的类型来赋值。

2.1 联合类型实例

let numType:string|number = "hello word";
numType = 20;  // 不会报错

2.2 接口

接口可以理解为一种类型,一个规范,一个约束,可以对数组、对象、类进行约束,接口中可以定义可选属性、只读属性、任意属性,这样在开发代码时便于调试。

interface Istate {  // 接口关键字为 interface  接口名字必须为大写的I字开头  state为接口名
  name:string;
age:number;
}  
let user:Istate = {
  name: '张三';
  age: 10;
}

2.2.1 接口可选属性

interface Istate {  // 接口关键字为 interface  接口名字必须为大写的I字开头  state为接口名
  name:string;
  age?:number; //  ?表示可选属性
}  
let user:Istate = {
  name: '张三';
  age: 10;  
}

2.2.2 接口只读属性

interface Istate {  // 接口关键字为 interface  接口名字必须为大写的I字开头  state为接口名
  readonly name:string;   // 表示只读
  age?:number; 
}  
let user:Istate = {
  name: '张三';
  age: 10;  
}
user.name = '李四'; // 报错,因为name为只读属性

2.2.3 接口也支持联合类型

interface Istate {  // 接口关键字为 interface  接口名字必须为大写的I字开头  state为接口名
  readonly name:string;   // 表示只读
  age:number|string; 
}  
let user:Istate = {
  name: '张三';
  age: 10;  
}
user.age= '20'; // 不报错

2.2.4 接口动态添加属性

interface Istate {  // 接口关键字为 interface  接口名字必须为大写的I字开头  state为接口名
  readonly name:string;   // 表示只读
  age?:number;   
  [propName:string]:any;  // propName自定义名称,属性名为string ,属性值为任意类型数据
}  
let user:Istate = {
  name: '张三';
  age: 10;  
  money: 20000000;
} // 不会报错

2.2.5 接口约束数组

interface IArray{
  [index:number]:any; // index为索引值,所以必须时数字类型,每个元素的值可以任意类型
}  
let arr:IArray = [1, 2, 3, true, '666'];  // 不会报错

3. 数组与元组

3.1 数组

数组对象是使用单独的变量名来存储一系列的值。常见的定义方式分别为:

  1. 类型+方括号
let arr1:number [] = [1, 2, 3,  4, 5];  
let arr2:string [] = ['1', '2', '3', '4', '5'];
let arr3:any [] = [1, '2', true];
  1. 数组泛型
let arr1:Array<number> = [1, 2, 3,  4, 5];  
let arr2:Array<string> = ['1', '2', '3', '4', '5'];
let arr3:Array<any> = [1, '2', true]; 

3.2 元组约束

let arr4:[string, number, boolean] = ["1", 2, true];
let arr5:[{ name:string, age:number }, { name:string, age:number }] = [
  { name: "张三", age: 18 }, { name: "李四", age: 20 }
]

4. 函数类型

函数类型的约束支持函数本身的参数约束和返回值的约束,如果支持联合类型的函数关系可以使用重载的方式。

4.1 参数约束和返回值约束的函数

function funType(name:string, age:number):number {
  return age;
}
let ageNum:number = funType("张三", 18);

4.2 函数参数为可选参数

function funType(name:string, age:number, gender?:string ):string {
  return name;
}

4.3 函数动态参数

函数参数不确定,使用扩展运算符来定义动态参数

function funType(name:string, age:number, ...args:any):any {
  return args;
}

4.4 函数参数默认值

function funType(name:string = "张三", age:number = 20):number {
  return age;
}

4.5 表达式声明函数

let funType:(name:string, age:number) => number = function(name:sstring = "张三", age:number = 20):number {
  retrun age;
}

4.6 接口约束函数

interface IFunType {
  (name:string, age:number):number;
}
let funType:IFunType = function(name:string, age:number):number {
  return age;
}

4.7 联合类型函数

联合类型的函数可以使用重载方式实现

// 重载  
function getValue(value:number):number;
function getValue(value:string):string;
// 联合类型函数
function getValue(value:string|number):string|number {
  return value;
}
let val:string = getValue("张三");
let val2:number = getValue(18);

函数重载必须写在函数声明前面

4.8 无返回值的函数

function fun():void {
  let age = 20;
}

5. 类型断言

类型断言可以用手动指定一个值的类型,将一个联合类型的变量指定为一个更加具体的类型。

function getAssert(name:string|number) {
  // return (<string>name).length; // <string>name类型断言,不支持jsx
  return (name as string).length; // 使用as实现类型断言,在jsx(react中的ts版)中使用这种方式
}
getAssert("张三");
getAssert(30);

注意:类型断言不是类型转换,断言成一个联合类型不存在的类型是不允许的。

6. 类型别名

类型别名可以用来给一个类型起一个新名字,采用关键字type定义,可以设置字符串和数值类型。

6.1 约束数值类型

type strType = string|number|boolean;
let str:strType = "张山";
str = 20;
str = true;

6.2 约束字符串

type gender = "男"|"女";  
function getGender(s:gender):sring {
  return s;
}
getGender("男");

7. 枚举

枚举(enum)类型是对JavaScript标准数据类型的一个补充,用于取值被限定在一定范围内的场景,定义数据集合,枚举成员会被赋值为从0开始递增的数字,同时也会被枚举到枚举名及逆行反向映射。

7.1 枚举双向映射

enum Days {
  Sunday,
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday
}
console.log(Days.Sunday); // 0 使用枚举名Sunday,可以获取到枚举0
console.log(Days[0]); // Sunday 使用枚举值0,可以获取到枚举名
console.log(Days.Saturday); // 6
console.log(Days[6]); // Saturday
console.log(Days); // 枚举类型会被编译成一个双向映射的对象  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
 /* 用ts-node编译得到如下结果 */
0
Sunday  
6       
Saturday
{ '0': 'Sunday',
  '1': 'Monday',
  '2': 'Tuesday',
  '3': 'Wednesday',
  '4': 'Thursday',
  '5': 'Friday',
  '6': 'Saturday',
  Sunday: 0,
  Monday: 1,
  Tuesday: 2,
  Wednesday: 3,
  Thursday: 4,
  Friday: 5,
  Saturday: 6 }

7.2 枚举从0开始递增

枚举里面的元素默认情况下从0开始为元素的编号,也可以手动的指定成员的编号,代码示例如下:

enum Colors {
  Red = 10,
Green = 9,
Blue = 1000
}
console.log(Colors);  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{ '9': 'Green',
  '10': 'Red',
  '1000': 'Blue',
  Red: 10,
  Green: 9,
  Blue: 1000 }

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
enum Colors {
  Red = 10,
Green,
Blue
}
console.log(Colors);  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{ '10': 'Red',
  '11': 'Green',
  '12': 'Blue',
  Red: 10,
  Green: 11,
  Blue: 12 }

8. 类的修饰符

在typescript中的类的修饰符有public、private、protected三个修饰符:

  • public修饰的属性或方法是共有的,可以在任何地方被访问到,默认所有的属性或方法都有public的。
  • private修饰的初次那个或者方法是私有的,不能在声明它的类外面访问,只能在本类内部访问使用。
  • protected修饰的属性或方法是受保护的,它和private类似,唯一的区别是可以在继承的类中访问,比如父类的protected成员为子类的protected成员,只允许子类成员访问。
class Person{
  public  name = "张三";
  private age = 20;
  protected gender = "男";
  // 内部访问
  public show() {
    console.log(this.name, this.age, this.gender)  // 张三 20 男
  }
}
let P = new Person()
console.log(P.name) // 张三
// console.log(P.age)  // 报错类型“typeof Person”上不存在属性“age”。
// console.log(P.gender) // 报错类型“typeof Person”上不存在属性“gender”。
P.show()
// 继承可访问protected
class Child extends Person{
  public run() {
    console.log(this.name)
    // console.log(this.age)  // 报错   属性“age”为私有属性,只能在类“Person”中访问
    console.log(this.gender)
  }
}
let children = new Child()
children.run()

9. 类的接口约束

在面向对象编程中,接口时一种规范的定义,它定义了行为和动作规范,在开发大型项目时通常采用面向对象的编程思路,那么就要用到接口约束,实现高内聚低耦合的代码规范。

9.1 继承一个接口

// 定义接口
interface ISuperMan {
  age:number;
  name:string;
  fly:Function;
}
// 使用implements关键字继承类接口  
class Man implements ISuperMan {
  age:number = 30;
  name:string = "超人";
  fly() {
    console.log(this.name + "不会飞");
  }
}
let person = new Man();
person.fly();  // 超人不会飞

9.2 继承多个接口

interface ISuperMan {
  name:string;
  age:number;
  fly:Function;
}
interface IFlashMan {
  run:() => void;
}
interface IIceKiller {
  ice:Function;
}
class Man2 implements ISuperMan, IFlashMan, IIceKiller {
  name:string = "合体";
  age:number = 12;
  fly() {
    console.log("不会跑");
  }
  run() {
    console.log("不会飞")
  }
  ice() {
    console.log("不会冰冻")
  }
}

9.3 一个接口继承多个接口

interface ISuperMan {
  name:string;
  age:number;
  fly:Function;
}
interface IFlashMan {
  run:() => void;
}
interface IIceKiller {
  ice:Function;
}
interface Man extends ISuperMan, IFlashMan, IIceKiller {
  
}

10. 泛型

10.1 泛型定义

泛型是指定义在函数、接口或类的时候,不预先指定具体类型,而在使用的时候指定类型的一种特性,比如定义一个带有参数的函数,未来在调用这个函数时,出入的值类型不确定,有可能是string,也有可能是number,这时可以使用泛型来解决这样的问题。

function createArray<T>(ltenth:number, value:T):Array<T> {
  let arr = [];
  for (let i = 0; i < length; i++) {
    arr[i] = value;
  }
  return arr;
}
var strArray:string [] = createArray<string>(3, "1");  // 使用这个函数
console.log(strArray); // 结果:["1", "2", "3"]
var numArray:number [] = createArray<number>(3, 2); // 如果不传<number>可进行类型推断
console.log(numArray); // 结果:[2, 2, 2]

10.2 多个泛型参数的函数

// 一个函数可以有多个泛型参数
function createMan<T, K>(name:T, age:K):[T, K] {
  return [name, age];
}
let result = createMan<string, number>("张三", 30);
console.log(result[0], result[1]); // 张三  30

10.3 泛型接口

在定义接口时,可以为接口中的属性或方法定义泛型类型,在使用接口时,指定具体的泛型类型。

  • 泛型接口在函数中的使用
interface ICreate {
  <T>(name:string, age T):string
}
let func: ICreate = function<T>(name:string, age:T):string {
  return name + "," + age
}
func<number>("李四", 20); // 李四,20

10.4 泛型接口在类中的使用

// 定义泛型接口
interface IUser<T> {
 name:string;
 age:number;
 getUserInfo: () => T
}
// 创建一个类使用泛型接口
class User implements IUser<string> {
 public name:string;
 public age:number;
 constructor(name:string, age:number) {
   this.name = name;
   this.age = age;
 }
 getUserInfo() {
   return `姓名${this.name}, 年龄${this.age}`;
 }
}
let user = new User("张三", 30);
console.log(user.getUserInfo()); // 姓名张三,年龄30

10.5 泛型类

泛型类是在定义类时,为类中的属性或方法定义泛型类型,在创建类的实例时,再指定特定的泛型类型。

class Counter<T> {
  public num:T;
  total(prixe:T, amount: T) {
    return Number(price) * Number(amount); // 如果需要计算必须转成Number类型
  }
}
let ct1 = new Counter<number>();
ct1.num = 10;
ct1.total(100, ct1, num);

let ct2 = new Counter<string>();
ct2.num = "100";
ct2.total("200", ct2.num);

10.6 泛型约束

泛型约束是指确保泛型类型使用的参数是提供特定方法的类型,比如直接对一个泛型参数使用length属性或是用push()方法,会报错,因为这个泛型根本不知道它有这个属性或是这个方法,使用泛型约束可以解决这一问题。

interface IArrayFunc {
  // 可以在setArray函数中使用push()方法
  push:Function;
  // 可以在setArray中使用length属性
  length:number;
}
function setArray<T extends IArrayFunc>(data:T, value:string|number) {
  data.push(value);
  console.log(data); // [1, 2, 3, '4'];
  console.log(data.length); 
}
setArray([1, 2, 3, "4"]);

11. 命名空间

命名空间主要用于组织代码,避免命名冲突,解决重名的问题,在代码量较大的情况下,为了避免各种变量命名相冲突,可将相似功能的函数、类、接口等放置到命名空间内,TypeScript的命名空间使用namespace关键字创建,可以将代码包裹起来,如果需要在外部访问命名空间内的接口或是类,则需要在类和接口添加export关键字。

namespace A {
  export let message = "大家好";
  export class Person {
    public name:string = "张三";
    public say() {
      console.log("大家好,我是" + this.name);
    }
  }
}
console.log(A.message);
let person = new A.Person();
console.log(person.name);
person.say();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,406评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,976评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,302评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,366评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,372评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,457评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,872评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,521评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,717评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,523评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,590评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,299评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,859评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,883评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,127评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,760评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,290评论 2 342

推荐阅读更多精彩内容