TS基础语法(一)

1. 什么是TS?

1.1 简介

TypeScript是⼀个开源的编程语⾔,通过在JavaScript的基础上添加静态类型定义构建⽽成。通过TypeScript编译器或Babel转译为JavaScript代码,可运⾏在任何浏览器,任何操作系统。

1.2 TS与JS的关系

TypeScript是JavaScript的⼀个超集,他们之间并不是所属关系,TypeScript扩展了JavaScript弱类型语⾔的限制,增加了更多的模块解析⽅式和语法糖。TypeScript并不是⼀个能独⽴运⾏的语⾔,⼤多数时候他都被转译成 JavaScript运⾏,所以可以简单的认为TypeScript相当于功能更丰富的编译型的JavaScript。

1.3 为什么要使用TS

JavaScript本身已完全可以满⾜完整的应⽤开发需求,但在⼤型项⽬协作开发或插件开发的场景中 JavaScript弱类型语⾔的不⾜便暴漏出来。由于JavaScript并⾮编译型语⾔,在代码编写过程中⽆法轻松的实现良好的类型约束和类型推断。TypeScript强类型的约束性以及其⾯向接⼝编程的约束性可以让TypeScript语法开发的应⽤有极强的 维护性,代价是更⼤量的代码篇幅。

1.4 TypeScript的性能优于JavaScript?

TypeScript通过编译后最终还是会转换为JavaScript,最终执行的还是JavaScript,并不能代表性能优势。TypeScript语⾔之所以流⾏,是因为其类型化的JavaScript,在上下⽂阅读时可以提供更好的类型追溯,通过编辑器插件可已实现更有好的提示。

2. TS入门

2.1 环境配置

中文文档地址:https://www.tslang.cn/index.html

打开电脑的命令⾏⼯具执⾏TypeScript引擎安装命令:

npm install typescript -g // 全局安装

tsc -v // 查看版本号

2.2 Hello Word 实现

新建index.ts文件,用编辑器打开输入以下代码:

let str:string = 'Hello Word';
console.log(str);

打开终端输入tsc,就自动编译出对应的index.js文件。输入node index.js完成终端编译js代码,打印输出Hello Word ;

3. 基础类型

在JavaScript的基础上新增了几种数据类型,在定义值时要声明值的类型。let 变量名:变量类型 = 变量值注意:类型是内置的时首字母建议小写,自定义定义的接口类型建议首字母大写。

3.1 JS内置类型
let big: bigint = BigInt(10);
let sym: symbol = Symbol("lin"); 
let num1:number = 1;
let str1:string = "1";
let unde1:undefined = undefined;
let null1:null = null;
let boo:boolean = true;
boo = 'false'; // 报错 不能将类型“string”分配给类型“Boolean”
3.2 any

不清楚用什么类型,可以使用 any 类型。这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。注:切勿滥用,不然就变成anyScript

let num:any = 0;
num = '0';
num = true;
// 上面定义了一个num类型为any,可以给他赋值为任意类型。完全失去了TS的作用
3.3 unknown

当不知道一个类型具体是什么时,该怎么办?可以使用 unknown 类型,它代表任何类型,它的定义和 any 定义很像,但是它是一个安全类型,使用 unknown 做任何事情都是不合法的。例如:

function getCount(num: unknown) {
  return num / 2;
}
// 会提示错误:对象的类型为 "unknown"
// 解决方案
function getCount(num: unknown) {
  return num as number / 2; // as为类型断言,将参数转换为number类型
}
3.4 void

void类型与 any 类型相反,它表示没有任何类型。比如函数没有明确返回值,默认返回 Void 类型

function seeHello(): void {
    console.log('hello')
}
3.5 never

never类型表示的是那些永不存在的值的类型。

有些情况下值会永不存在,比如:

  • 如果一个函数执行时抛出了异常,那么这个函数永远不存在返回值,因为抛出异常会直接中断程序运行。
  • 函数中执行无限循环的代码,使得程序永远无法运行到函数返回值那一步。
// 异常
function showError(msg: string): never { 
  throw new Error(msg)
}

// 死循环
function showLoop(): never { 
  while (true) {}
}
3.6 object
可以直接定义值为对象类型,也可以定义特定的接口对象来规范对象中每个值的类型(后面会提到);
const obj:object = {
  name: '小明'
}
obj.age = 23;  // 报错 类型“object”上不存在属性“age”
// 解决方案
// Record是TS中内置工具类型,接收两个泛型参数
const obj1:Record<string, any>  = {} // 规范Obj1对象每一项键名必须是字符串,值的类型可以是any类型

注意:声明对象时要规范数组每一项的类型,新添加一个不存在的值会导致语法错误。

3.6 Array数组类型

格式为:let 变量名:数组中类型[] = 变量值注意:数组中的值一定要与定义的类型对应上要不然就会报错;

// 定义了一个数组每一项都是number类型的数组
let list: number[] = [1, 2, 3]
list.push(4)
list.push('5')  // 报错 类型“string”的参数不能赋给类型“number”的参数。

如果数组想每一项放入不同数据怎么办?用元组类型

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。

let list: [number,string,boolean] = [1, '2', true];
list.push(null); // 报错 因为元祖类型中没有null类型定义

4. 函数类型

TS 定义函数类型需要定义输入参数类型和输出类型。输出类型也可以忽略,因为 TS 能够根据返回语句自动推断出返回值类型。

function add(x:number, y:number):number {
  return x + y
}
console.log(add(1,2)); // 3
// 函数表达式
let add2 = (x: number, y: number) => {
    return x + y
}
console.log(add(1,4)); // 5
console.log(add(1,'5')); // 报错 类型“string”的参数不能赋给类型“number”的参数。
4.1 可选参数:

参数后加个问号,代表这个参数是可选的

function add(x:number, y:number, z?:number):number {
    return x + y
}

console.log(add(1,2,3),add(1,2)); // 3 3
4.2 默认参数:

跟 JS 的写法一样,在入参里定义初始值。和可选参数不同的是,默认参数可以不放在函数入参的最后面,

function add(x:number = 100, y:number):number {
    return x + y
}
console.log(add(1,4)); //  5
console.log(add(undefined,100)); // 200  当x为undefined会使用默认值
4.3 函数重载:

函数重载是指两个函数名称相同,但是参数个数或参数类型不同,他的好处显而易见,不需要把相似功能的函数拆分成多个函数名称不同的函数。

function add(x: number[]): number
function add(x: string[]): string
function add(x: number[], y: number[]): number
function add(x: string[], y: string[]): string
function add(x: any[], y?: any[]): any {
  if (Array.isArray(y) && typeof y[0] === 'number') {
      return x.reduce((acc, cur) => acc + cur) + y.reduce((acc, cur) => acc + cur)
  }
  if (Array.isArray(y) && typeof y[0] === 'string') {
      return x.join() + ',' + y.join()
  }
  if (typeof x[0] === 'string') {
    return x.join()
  }
  if (typeof x[0] === 'number') {
      return x.reduce((acc, cur) => acc + cur)
  }
}
console.log(add([1,2,3]))      // 6
console.log(add(['1', '2']))  // '1,2'
console.log(add([1,2,3], [1,2,3])) // 12
console.log(add(['1', '2'], ['3', '4'])) // '1,2,3,4'

注意:在 TS 中,实现函数重载,需要多次声明这个函数,前几次是函数定义,列出所有的情况,最后一次是函数实现,需要比较宽泛的类型

5 interface接口

interface(接口) 是 TS 设计出来用于定义对象类型的,可以对对象的形状进行描述。定义 interface 一般首字母大写,如下:

interface Person {
    name: string
    age: number
}

const son: Person = {
    name: '张三'
}
// 报错 类型 "{ name: string; }" 中缺少属性 "age",但类型 "Person" 中需要该属性。
// 变量用了Person接口但是未定义age属性,导致报错;同时多写属性也会报错

注意:interface 不是 JS 中的关键字,所以 TS 编译成 JS 之后,这些 interface 是不会被转换过去的,都会被删除掉,interface 只是在 TS 中用来做静态检查

5.1 可选属性

跟函数的可选参数是类似的,在属性上加个 ?,这个属性就是可选的。

interface Person {
    name: string
    age?: number
}
const son: Person = {
    name: '张三'
}
5.2 只读属性

如果希望某个属性不被改变,

interface Person {
    readonly id: number
    name: string
    age: number
}
const son: Person = {
    id: 2,
    name: '张三',
    age: 20
}
son.id = 3; // 报错 无法分配到 "id" ,因为它是只读属性
5.3 描述函数类型

interface 也可以用来描述函数类型

interface ShowFn {
  (x:number,y:number):number
}
const add:showFn = (num1, num2) => {
  return num1 + num2
}
5.4 自定义属性(可索引的类型)

当一个对象上有多个不确定的属性时,就可以使用自定义属性。

interface ShowRandom {
    [key: number]: number
}

const arr: ShowRandom = {
    0: 0,
    1: 1,
    2: 2,
}
// 还可以这样写
const arr1:ShowRandom = [0,1,2]// 看似想一个数组,其实是一个类数组,不能调用数组的属性和方法
5.5 duck typing(鸭子类型)

interface 的写法非常灵活,用 interface 可以创造一系列自定义的类型。所以interface 还有一个响亮的名称:duck typing(鸭子类型)。 例如:


interface ShowFn {
  (num1:number ,num2:number):number;
  name: string;
}
const fn:ShowFn = (num1,num2) => {
  return num1 + num2
}
fn.name = "函数"; 

上面这个接口中函数类型添加了一大堆属性,完全四不像,但是却是完全正常的工作。这就是 duck typing 和 interface,非常的灵活。

你可能感兴趣的:(TypeScript,javascript,typescript,前端)