ts知识点
安装
npm install typescript -g
yarn global add typescript
执行
tsc Demo1.ts
npm install -g ts-node
ts-node Demo1.ts
静态类型
- : number 就是定义了一个静态类型
- 如果使用了静态类型,不仅意味着变量的类型不可以改变,还意味着类型的属性和方法也跟着确定了
const count: number = 1;
基础类型 && 对象类型
- 基础静态类型,只要在声明变量的后边加一个:号,然后加上对应的类型,
number string null undefined symbol boolean void
const count : number = 918;
- 对象类型可以有几种形式:对象类型、数组类型、类类型、函数类型
const arr: String[] = ["sds", "sdsd", "sdw"];
const kk: () => string = () => { return "sdsd";};
类型注解 && 类型推断
- 类型注解如
const count:number = 12
- 如果 ts 能够自动分析变量类型,我们可以不定义;如果 ts 无法分析变量类型,就需要使用类型注解;
- total 这个变量不需要加类型注解:当 one 和 two 两个变量加上注解后,TypeScript 就可以自动通过类型推断,分析出变量的类型;
- 在写 TypeScript 代码的一个重要宗旨就是每个变量,每个对象的属性类型都应该是固定的,如果你推断就让它推断,推断不出来的时候你要进行注释
function getTotal(one:number, two:number){
return one + two;
}
const total = getTotal(1,2);
函数参数和返回类型定义
- 函数有返回值
function getTotal(one:number, two: number): number{
return one + two;
}
const total = getTotal(1,2)
- 函数无返回值,void
function sayHello(): void {
console.log('hello-);
}
- never 返回值类型 函数抛出异常 || 死循环情况
function errFunc(): never {
throw new Error();
console.log('hello~);
}
function forNever(): never{
while(true){}
console.log(hl-);
}
- 函数参数为对象(解构)时
function add({one, two}: {one: number, two: number}): number {
return one + two;
}
const total = add({one:1, two:2});
function getNumber({one}: {one: number}): number{
return one;
}
const num = getNumber({one:8});
数组类型的定义
- 一般数组类型的定义
const numberArr = [1,2,3] // ts可以自己推断,不加类型也可以
const numberArr: number[] = [1,2,3];
const strArr: string[] = ['1', '2'];
const undefinedArr: undefined[] = [undefined, undefined];
const arr: (number | string)[] = [1,'2',3];
- 数组中对象类型的定义
const arr: {name: string, age:number}[] = [
{name:'ssd', age:12},
{name:'sdsd, age: 123},
]
- 类型别名(也可以实现代码重用),等价于上面写法
type ArrItem = {name: string, age: number}
const arr: ArrItem[] = [
{name:'ds', age:12},
{name:'233', age:8},
]
- class 类定义也可以
class ArrItem {
name: string,
age: number,
}
const arr: ArrItem[] = [
{name: '12', age: 12},
{name:'dfdf', age:89},
]
元组的使用和类型约束
- 解决多个类型时候类型注解不准确的问题,如希望得到这种
const aa: (string | number)[] = ['ss', 'sdw', 12];
但const aa: (string | number)[] = [12, 'sdw', 12];
这种也不会报错,,此时可借助元组解决问题;- 元组:
const arr: [string, string, number] = ['ss', 'sdsd', 18];
interface
- 接口,就是用来规范类型的。
- 把多个重复的类型注解,定义成统一的接口;
interface Person {
name: string,
age: number,
height: number,
}
const getPerson = (person: Person) => {
peraon.age < 24 && person.height > 160 && console.log(person.name + 'ok');
peraon.age > 24 && person.height < 160 && console.log(person.name + 'no ok');
}
- 接口和类型别名的区别:
- 类型别名可以直接给类型如
type Person = string;
,而接口必须代表对象,即初始化 person 时,必须写成这种形式const person = {name: 'ss', age: 12, height: 179}
- 接口可以定义非必选值类型
interface Person {
name: string;
age: number;
height?: number;
}
- 接口允许加入任意值
interface Person {
name: string;
age: number;
height?: number;
// 任意值,属性名字是字符串类型,属性值可以是任何类型
[propname: string]: any,
}
const person = {
name: 'kk',
age: 12,
sex: 'nv'
}
- 接口里的方法,接口不仅可以存属性,还可以存方法
interface Person {
name: string;
age: number;
height?: number;
[propname:string]: any;
say(): string;
}
const person = {
name: 'kk',
age: 13,
height: 190,
say(){
return 'hello~';
}
}
- 接口和类的约束,实现 && 继承
class XY implements Person {
name = 'k';
age = '13';
height = 120;
say() {
return 'hello--'
}
}
interface Teacher extends Person {
teach(): string;
}
const person = {
name: 's',
age: 12,
height: 190,
say() {
return 'kk'
},
teach() {
return 'mm'
}
}
const getResume = (person: Teacher) = > {
console.log('kkk');
}
类
- 基本使用
class Person {
content = "hi";
sayHi(){
return this.content;
}
}
const person = new Person();
console.log(person.sayHi());
- 类的重写:子类可以重新编写父类里边的代码;
class XY extends Person {
sayHi(){
return 'hi, girl';
}
sayWorld() {
return 'hello world'
}
}
- super:使用 super 关键字,它代表父类中的方法
class XY extends Person {
sayHi(){
return super.sayHi() + "---你好世界";
}
}
类的访问类型: public/protected/private
- public, 公共的,允许在类的内部和外部被调用.
class Person {
public name:string;
public sayHello(){
console.log(this.name + 'say Hello')
}
}
//-------以下属于类的外部--------
const person = new Person()
person.name = 'jspang.com'
person.sayHello()
console.log(person.name)
- private, 私有的,只允许在类的内部使用
class Person {
private name:string;
public sayHello(){
console.log(this.name + 'say Hello') //此处不报错
}
}
//-------以下属于类的外部--------
const person = new Person()
person.name = 'jspang.com' //此处报错
person.sayHello()
console.log(person.name) //此处报错
- protected, 允许在类内及继承的子类中使用
class Person {
protected name:string;
public sayHello(){
console.log(this.name + 'say Hello') //此处不报错
}
}
class Teacher extends Person{
public sayBye(){
this.name;
}
}
类的构造函数
- 构造函数:在类被初始化时候自动执行的一个方法。
- Person 类,类的里边定义一个 name,但是 name 我们并不给他值,然后我们希望在 new 出对象的时候,直接通过传递参数的形式,给 name 赋值,并打印出来。这时候我们就需要用到构造函数了,构造函数的关键字是 constructor
class Person {
public name: string;
constructor(name: string){
this.name = name;
}
}
const person = new Person('sds');
console.log(person.name);
class Person {
constructor(public name: string){}
}
const person = new Person('kk');
console.log(person.name);
- 类继承中的构造器写法
class Person {
constructor(public name: string) {}
}
class Teacher extends Person {
constructor(public age: number){
super('js')
}
}
const teacher = new Teacher(19);
console.log(teacher.age);
console.log(teacher.name);
- 这就是子类继承父类并有构造函数的原则,就是在子类里写构造函数时,必须用 super()调用父类的构造函数,如果需要传值,也必须进行传值操作。就是是父类没有构造函数,子类也要使用 super()进行调用,否则就会报错.
Getter/Setter/static
- 访问类型的用途:封装一个属性,然后通过 Getter 和 Setter 的形式来访问和修改这个属性
类的只读属性和抽象类
- readonly
class Person {
public readonly name: string;
constructor(name: string){
this.name = name;
}
}
- abstract
abstract class Person {
abstract skill()
}
class A extends Person {
skill(){
console.log('A 技能');
}
}
class B extends Person {
skill(){
console.log('B 技能');
}
}
class C extends Person {
skill(){
console.log('C 技能');
}
}
tsconfig.json
- tsc --init 生成
- 使得配置文件生效,使用 tsc 命令,而不是 ts-node 命令
- 写配置文件时有个坑需要注意,就是配置文件不支持单引号,所以里边都要使用双引号
- include 属性是用来指定要编译的文件的,
- exclude 是不包含,除什么文件之外的文件才进行编译。
- compilerOptions 配置项:告诉 TypeScript 具体如何编译成 js 文件的
联合类型 && 类型保护
- 联合类型:一个变量可能有两种或两种以上的类型。 '|'表示。 如
const a: Waiter | Teacher
;a 可能是 Waiter 类型(有 wa 方法),也可能是 Teacher 类型(有 ta 方法),如果直接调用 wa 方法,是会报错的,因为 a 也可能是 Teacher 类型就没有 wa 方法,此时就需要用到类型保护了。
- 类型保护
- 类型断言:通过断言的方式确定传递过来的准确值,
- in 语法
- typeof 语法
- instanceof 语法
- 类型保护-类型断言
interface Waiter {
aa: boolean;
say: () => {};
}
interface Teacher {
aa: boolean;
skill: () => {};
}
function judgeWho(a: Waiter | Teacher) {
// aa为true说明是Waiter类型
if (a.aa) {
(a as Waiter).say();
} else {
(a as Teacher).skill();
}
}
- 类型保护-in 语法
function judgeWho(a: Waiter | Teacher) {
if ('skill' in a) {
a.skill();
} else {
a.say();
}
}
- 类型保护-typeof
function add(first: string | number, second: string | number) {
if(typeof first === 'string' || typeof second === 'string'){
return `${first}${second}`;
}
return first + second;
}
- 类型保护-instanceof 语法
class NumberObj {
count: number;
}
function addObj(first: object | NumberObj, second: object | NumberObj) {
if(first instanceof NumberObj && second instanceof NumberObj) {
return first.count + second.count;
}
return 0;
}
Enum 枚举类型
enum Status {
a,
b,
c
}
function get(status: any) {
if(status === Status.a){
return 'aaaa'
} else if (status === Status.b) {
return 'bbbb'
} else if (status === Status.c) {
return 'cccc'
}
}
const result = get(Status.a)
console.log(result);
泛型
- 通用-泛指的类型,<>包裹,如
来作泛型的表示
- 泛型中数组的使用
const arr: number[] = [1,2,3]
const arr: Array<number> = [1,2,3] // 泛型
- 一个函数可以定义多个泛型,
function join<T, P>(first: T, second: P) {
return `${first}${second}`;
}
join<number, string>(1, '2');
- 类型约束
// 泛型约束
class A<T extends number | string> {}
搭建继承的 TS 开发环境
- 建立好文件夹后,打开 VSCode,把文件夹拉到编辑器当中,然后打开终端,运行 npm init -y,创建 package.json 文件。
- 生成文件后,我们接着在终端中运行 tsc -init,生成 tsconfig.json 文件。
- 新建 src 和 build 文件夹,再建一个 index.html 文件。
- 在 src 目录下,新建一个 page.ts 文件,这就是我们要编写的 ts 文件了。
- 配置 tsconfig.json 文件,设置 outDir 和 rootDir(在 15 行左右),也就是设置需要编译的文件目录,和编译好的文件目录。
- 然后编写 index.html,引入,当让我们现在还没有 page.js 文件。
- 编写 page.ts 文件,加入一句输出 console.log('jspang.com'),再在控制台输入 tsc,就会生成 page.js 文件
- 再到浏览器中查看 index.html 文件,如果按 F12 可以看到 jspang.com,说明我们的搭建正常了。
命名空间
namespace moduleName {}
- 提供的类似模块化开发的语法,让全局变量减少了很多,实现了基本的封装,减少了全局变量的污染。
Parcel 打包 ts
yarn add --dev parcel@next
示例
// 变量声明,给JavaScript中的基础类型使用的
let val:number = 1;
let val2:string = "1";
let val3:boolean = true;
// 接口,给对象这种复杂的类型使用的,当我们有一个对象的时候,可以通过接口整体的来描述这个对象
interface person {
name: string,
age?: number, //表示age这个属性可能存在,也可能不存在
}
// xm是一个对象,而JavaScript中没有xm这种数据类型,我们定义的接口person就可以用来描述xm的数据类型
const xm:person = {
name: 'kk',
age: 16
}
// 当给函数添加了类型后,调用的时候,就可以清楚的看到这个函数需要什么类型的参数,会返回什么样的参数,
// 函数
interface Fun {
(num: number, str: string): string
}
const fun: Fun = (num, str) => {
return '123'
}
// 类
class Person {
name: string,
constructor(name: string) {
this.name = name;
}
}
let xx = new Person('kk');
// vue中使用
<script setup lang="ts">
// ts中,定义count的时候,默认值给的是数字1,对count的value赋值也应该是数值
let count = ref(1);
count.value = 2;
// 定义一个字符串或数字类型的响应式变量
let count = ref<string | number>('1');
count.value = 1;
interface Person {
name: string,
age: number
}
let person = reactive<Person>({
name: 'xx',
age: 18
})
let person2: Person = reactive({
name: 'xx',
age: 14
})
let person3 = reactive({
name: 'xx',
}) as Person;
// 在Vue中还有props和emits也可以申明变量,通过泛型的方式来添加类型
// ts不认识.vue文件,所以需要添加一个声明文件,在根目录下新建env.d.ts文件
declare module '*.vue' {
import type { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>
export default component;
}
// 泛型
export function ref<T>(value: T): T
// 也可以不用插入泛型,会自动根据传入的参数进行类型推导出来
let str = ref('string'); // ref<string>('string');
let num = ref(123); // ref<number>(123);
</script>
ts-技术胖
ts-技术胖
Vue3
宝剑锋从磨砺出,梅花香自苦寒来。