Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TS #41

Open
jinzhepro opened this issue Apr 21, 2023 · 0 comments
Open

TS #41

jinzhepro opened this issue Apr 21, 2023 · 0 comments
Labels

Comments

@jinzhepro
Copy link
Owner

类型声明

使用 :[type] 指定变量的类型

let a: number = 1 // 数字
let b: string = 'zhang' // 字符串
let c: boolean = true // 布尔
let d: object = {} // 对象
let e: array = [] // 数组
let f: null = null // Null
let g: undefined = undefined // Undefined
let h: void = function(){} // 空值
let i: any = [] // 表示任意类型,可以链式传播,不会对其进行类型检查
let j: unknown; // 表示不确定类型,只能赋值给unknown和any,会进行类型检测
let k: never; // 表示一个不可能出现的值,比如抛出错误,无限循环,并可以模拟只读属性
// 未声明类型的变量默认为any
let something === let something: any;

类型推论

如果没有指定类型,那么TS会按照类型推论推断出一个类型

let myFavoriteNumber = 'seven';
myFavoriteNumber = 7; // error

联合类型

表示可以取多个类型的一种

let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
// 只能访问联合类型的共有属性(类型推断)
function getLength(something: string | number): number {
return something.toString();
}

对象类型(interface)

我们使用接口(Interfaces)来定义对象的类型。

使用任意属性时,其他属性必须为任意属性的子集,可以使用联合类型

interface A {
  age: number, // 确定属性
  readonly name: boolean // 只读属性
  male?: number // 可选属性
  [propName: string]: string | number | boolean // 任意属性
}
let obj: A = {
  name: true,
  age: 12,
  zjang: '123',
}

数组类型

let fibonacci: number[] = [1, 1, 2, 3, 5]; // 类型 + []
let fibonacci1: Array<number> = [1, 1, 2, 3, 5]; // 数组泛型
interface NumberArray {
    [index: number]: number;
}
let fibonacci2: NumberArray = [1, 1, 2, 3, 5]; // 接口(类数组)

函数类型

函数声明

function sum(x: number = 123, y?: number): number { // 校验输入和输出
  return x + y;
}
sum(1, 2);
// 可设置默认值
// 可选参数后不允许再出现必须参数

函数表达式

let sum:(x: number, y: number) => number = function (x: number, y: number): number {
  return x + y;
}
sum(1, 2);
// TS中=>表示的是函数定义,左边输入类型,右边输出类型

接口定义

interface SearchFunc {
(source: string, subString: string): boolean;
}
  let mySearch: SearchFunc;
  mySearch = function(source: string, subString: string) {
  return source.search(subString) !== -1;
}

重载

重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
  if (typeof x === 'number') {
    return Number(x.toString().split('').reverse().join(''));
  } else if (typeof x === 'string') {
    return x.split('').reverse().join('');
  }
}
// TS会优先从最前面的函数定义开始匹配,所以要把精确匹配放在前面

类型断言

可以手动指定一个值的类型:值 as 类型

将联合类型断言为其中一个类型

interface Cat {
  name: string;
  run(): void;
}
interface Fish {
  name: string;
  swim(): void;
}
function isFish(animal: Cat | Fish) {
  if (typeof (animal as Fish).swim === 'function') {
    return true;
  }
  return false;
}
// 需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误,比如执行了一个本不是它自己的方法。

将父类断言为更为具体的子类

interface ApiError extends Error {
  code: number;
}
interface HttpError extends Error {
  statusCode: number;
}
function isApiError(error: Error) {
  if (typeof (error as ApiError).code === 'number') {
    return true;
  }
  return false;
}

将任何一个类型断言为 any

window.foo = 1; // error
(window as any).foo = 1; // √

将 any 断言为一个具体的类型

function getCacheData(key: string): any {
  return (window as any).cache[key];
}
interface Cat {
  name: string;
  run(): void;
}
const tom = getCacheData('tom') as Cat;
tom.run();
// getCacheData可能是是一个第三方库,不确定他的返回类型,当我们在使用时

断言的限制-兼容

interface A {
  name: string;
}
interface B {
  name: string;
  run(): void;
}
let tom: B = {
  name: 'Tom',
  run: () => { console.log('run') }
};
let animal: A = tom; // √
// 若 A 兼容 B,那么 A 能够被断言为 B,B 也能被断言为 A
// 同理,若 B 兼容 A,那么 A 能够被断言为 B,B 也能被断言为 A

双重断言

interface Cat {
  run(): void;
}
interface Fish {
  swim(): void;
}
function testCat(cat: Cat) {
  return (cat as any as Fish);
}
let cat = {
  run() {
    console.log(1);
  }
}
testCat(cat).swim()
// 这是非常危险的,可能导致运行时错误

类实现接口implements

interface ClockInterface {
  currentTime: Date;
  setTime(d: Date);
}
class Clock implements ClockInterface { //
  currentTime: Date;
  setTime(d: Date) {
  this.currentTime = d;
}
constructor(h: number, m: number) {}
}

类修饰符static、public、private、protected

class Person {
  protected name: string // 行为类似private,但只可继承
  constructor(name: string){
    this.name = name
  }
}
class Zhang extends Person {
  constructor(name: string) {
    super(name)
  }
  static a = 'a' // 全局属性,创建全局变量
  public b = 'b' // 默认共有属性,内部外部都可访问
  private c = 'c' // 私有属性,外部不可访问
}
Zhang.a // a
new Zhang('zhang').b // b
new Zhang('zhang').c // error!
new Zhang('zhang').name // error!
new Person('zhang').name // error!

抽象类abstract

abstract class Person {
  private name: string // 行为类似private,但只可继承
  constructor(name: string){
    this.name = name
  }
  call(){
    console.log('call')
  }
  abstract show(): void
}
class Zhang extends Person {
  constructor(name: string) {
    super(name)
  }
  show(){
    console.log('show')		
  }
  bind(){
    console.log('bind')
  }
}
let zhang: Person // 允许创建一个抽象类型的引用
zhang = new Person('zhang') // error! 不允许实例化抽象类
zhang = new Zhang('zhang') // 可以实例化派生类
zhang.call()
zhang.show()
zhang.bind() // error! 没有该方法

泛型

要求传入的类型和返回的类型一致

interface A {
  (arg: T): T
}
let fun: A
fun(1)
// 将泛型接口当做整体类型的一个接口
interface B<T> {
  (arg: T): T
}
let fun: B<number>
fun("string") // error! 直观的看到类型
fun(123) // √
// 泛型约束
interface A {
  length: number
}
function a<T extends A>(arg: T): T{
  console.log(arg.length)
  return arg
}
a(123) // error! 参数arg必须符合接口A的规范
a([1,2,3]) // √
@jinzhepro jinzhepro added the TS label Apr 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant