TypeScript基础语法

一.简介

TypeScript是JavaScript的超集,增加了数据类型, 帮助JS检查错误, 防止在大型项目中JS出现解释错误.
TypeScript最后还是会编译成JS.

二. 类型

2.1 基本类型

let message: string = 'hello world 1';
let b: boolean = true;
let str: string | null | undefined = "|为联合语法"

//数组
let arr1: Array<number> = [10, 20 ,30]
let arr2: number[] = [2, 3, 4]
let arr3: Array<number | string> = [666, "真的666"]
//参数展开运算符
let arr5: number[] = [1, 2, 3]
let arr6: number[] = [4, 5]
arr5.push(...arr6)
console.log(arr5)//[LOG]: [1, 2, 3, 4, 5]

//元组
let tuple: [number, string] = [666, "这是元组"]
console.log(message, b, str, arr1, arr2, arr3, tuple);

//函数
let add = (x: number, y: number):number => x + y
console.log("合为"+add(1, 2))

//对象
let obj0: Object;
let obj: {x: number, y: number} = {x: 1, y: 2}
console.log("obj的值为" + obj.y)

//symbol 全局唯一引用
//symbol 类型表示一个独一无二的标识符。每个通过 Symbol 函数创建的 symbol 都是唯一的,即使它们的描述相同。
let s1: symbol = Symbol()
let s2 = Symbol()
// 创建一个唯一的 symbol
const mySymbol: symbol = Symbol("mySymbol");
// 创建另一个唯一的 symbol
const anotherSymbol: symbol = Symbol("mySymbol");
// 由于每个 symbol 都是唯一的,这两个 symbol 不相等
console.log(mySymbol === anotherSymbol);  // 输出: false

//undefined
let un: undefined = undefined;
let nu: null = null;
//message = null; //报错,因为启动了strictNullChecks(严格null校验)

//void
let noReturn = () => {}//let noReturn: () => void

//any, 变量的默认类型为any
let aaany //let aaany: any

//nerver
let error = () => {//let error: () => never
    throw new Error("error")
}
let endless = () => {//let endless: () => never
    while(true) {
    }
}

2.2 自定义类型


//let 可变参数
let aString = "hello"
aString = "world"

//const 不可变参数
const bString = "666"
bString = "777"//报错

//使用let来实现const, 将cString的类型定义为一个'can not changed string'这样一个特殊类型
//等号前后要保持一致,否则会报错
let cString: 'can not changed string' = "can not changed string"
cString = "yes"//报错

//使用特殊类型
function printText(text: string, aligment: "left" | "right" | "center") {
  console.log(text + "---" + aligment)
}
printText("label", "center")//[LOG]: "label---center" 

三. 枚举

//数字枚举
enum Season {
    Spring,
    Summer,
    Fall,
    Winter
}
console.log(Season.Spring)//0
console.log(Season.Fall)//2

//枚举的原理
//转化为JS
/*
"use strict";
var Season;
(function (Season) {
    Season[Season["Spring"] = 0] = "Spring";
    Season[Season["Summer"] = 1] = "Summer";
    Season[Season["Fall"] = 2] = "Fall";
    Season[Season["Winter"] = 3] = "Winter";
})(Season || (Season = {}));
console.log(Season.Spring); //0
console.log(Season.Fall); //2
*/


//字符串枚举
enum Message {
    Successs = "成功",
    Fail = "失败"
}
/*
var Message;
(function (Message) {
    Message["Successs"] = "\u6210\u529F";
    Message["Fail"] = "\u5931\u8D25";
})(Message || (Message = {}));
*/

//异构枚举
enum Anser{
    N,
    Y = "YES"
}
/*
var Anser;
(function (Anser) {
    Anser[Anser["N"] = 0] = "N";
    Anser["Y"] = "YES";
})(Anser || (Anser = {}));
*/


//枚举成员
enum Char {
    //const类型, 编译时确定值
    a,          //未定义
    b = Char.a, //对其他枚举的引用
    c = 1 + 3,  //常量

    //computed类型, 运行时计算确定值
    d = Math.random(),
    e = "123".length
}
/*
var Char;
(function (Char) {
    //const类型, 编译时确定值
    Char[Char["a"] = 0] = "a";
    Char[Char["b"] = 0] = "b";
    Char[Char["c"] = 4] = "c";
    //computed类型, 运行时计算确定值
    Char[Char["d"] = Math.random()] = "d";
    Char[Char["e"] = "123".length] = "e";
})(Char || (Char = {}));
*/

//常量枚举, 使用const声明; 不会被编译进代码, 相当于预编译的宏替换
const enum Month {
    Jan,
    Fri,
    Mar
}

//枚举类型
enum E {a, b}
enum F {a = 1, b = 2}
enum G {a = "hhh", b = "666"}

//let le: E = 3   //Type '3' is not assignable to type 'E'.
//let lf: F = 3   //Type '3' is not assignable to type 'F'.
let lg: G.a = G.a

四.类型接口

4.1 对象类型接口

interface list {
    readonly id: number,    //readonly, 只读属性
    name: string,
    age?: number            //?可选参数
}
interface list1 {
    readonly id: number,    //readonly, 只读属性
    name: string,
    age?: number            //?可选参数
}
//interface也可以继承
interface list2  extends list, list1{
}

interface StringArray {
    [index: number]:string
}
let chars: StringArray = ["A", "B", "C"]
console.log(chars[2])//C

interface Names {
    [x: string]:string | undefined,
    [index: number]:string
}
let names: Names = {
    0: "A",
    1: "B",
    "2": "C",
    "Wow": "真的6啊"
}
console.log(names[1], names["Wow"])//"B",  "真的6啊" 

4.2 函数类型接口

//普通函数变量, 不能被继承
let add0: (x: number, y: number) => number; //add0是一个函数类型的变量
add0 = function(x, y) {                     //给变量复制真正的函数体
    return x + y
}
console.log(add0(1, 2))// 3

//函数类型接口
interface Add1 {
    (x: number, y: number): number
}
let add1: Add1 = function (x, y){
    return x + y
}
console.log(add1(1, 5))//6

// 搞个别名
type Add2 = (x: number, y: number) => number
let add2: Add2 = (x, y) => x + y
console.log(add2(1, 9))//10

//可选参数, z可以不传, 且必须位于必选参数之后
function add5(x: number, y: number, defaultValue=6, z?: number) {
    return z ? x + y + defaultValue + z : x + y + defaultValue;
}
console.log(add5(1, 2), add5(1, 2, 3))//[LOG]: 9,  6 

五.类


//抽象类, 不能被实例化, 只能被继承
abstract class Animal {
    eat() {
        console.log("eat")
    }
}


class Dog extends Animal{
    name: string
    static food: string = "骨头"//类成员,使用类名调用
    constructor(name: string) {
        super()
        this.name = name
    }
    run() {

    }
}
console.log(Dog.prototype)

let d = new Dog("汪汪汪")
d.eat();
console.log(d, d.name)
/*
[LOG]: Dog: {
  "name": "汪汪汪"
},  "汪汪汪" 
 */


//哈士奇继承自Dog
class Husky extends Dog {
    color: string
    constructor(name: string, color: string) {
        super(name)
        this.color = color
    }
}

//哈士奇继承自Dog-> 给参数增加public属性,可以不用在类里面定义color: string了
class Husky1 extends Dog {
    constructor(name: string, public color: string) {
        super(name)
        this.color = color
    }
}


//private   也可以使用#变量来实现private
//protect
// public

六.类型断言

  • 使用as或者<>来类型断言
  • 类型断言会在运行时被删除
const m1 = document.getElementById("main") as HTMLCanvasElement
const m2 = <HTMLCanvasElement>document.getElementById("main")

七.类型缩小

7.1 使用typeof来实现类型守卫

let s: string | number = "astring"
// s = 666
if (typeof s === "string") {
   console.log("字符串")
} else if (typeof s === "number") {
     console.log("数字")
}

let ret: typeof s
ret = "0.0"

7.2 真值缩小

function havePeople(count: number | string | null | undefined) {
  if (count) {
    console.log("有人")
  } else {
    console.log("没人")
  }
}
//针对number 非0即为true
havePeople(-1)  //[LOG]: "有人" 
havePeople(0)   //[LOG]: "没人" 
havePeople(1)   //[LOG]: "有人" 

//针对string  非空字符串为true
havePeople("")  //[LOG]: "没人"
havePeople("h") //[LOG]: "有人"

//null和undefined都为false
havePeople(null)      //[LOG]: "没人"
havePeople(undefined) //[LOG]: "没人"

//或者使用一下方法 大写Boolean或者!!, !!其实就是取反再取反
console.log(Boolean(""))  //false
console.log(Boolean("h")) //true
console.log(!!0)          //false
console.log(!!1)          //true

7.3 等值缩小

使用== === != !===来实现
在 TypeScript 中,== 和 === 是用于比较值的操作符,它们的行为与 JavaScript 中的相同。

  • == 是松散相等性比较,也称为“不严格相等”。在比较时,会进行类型转换,尝试使两侧的值类型相同,然后再进行比较。
  • === 是严格相等性比较,也称为“严格相等”。它不进行类型转换,只有在类型和值都相同时才被认为相等。
let a: number = 5
let b: string = "5"
// 使用 ==
console.log(a == b);  // 输出: true,因为在比较时会进行类型转换
// 使用 ===
console.log(a === b);  // 输出: false,因为严格相等要求类型和值都相同

let n1 = 5
let n2 = 6
console.log(n1 == n2)//false
console.log(n1 === n2)//false

7.4 in

在 TypeScript 中,in 关键字主要用于检查对象是否包含某个属性。它可以用于两个场景:

  • 检查对象是否包含某个属性
let myObject = { key1: 'value1', key2: 'value2' };

if ('key1' in myObject) {
  console.log('myObject has key1 property');
} else {
  console.log('myObject does not have key1 property');
}
  • 遍历对象的属性
let myObject = { key1: 'value1', key2: 'value2' };
for (let key in myObject) {
  console.log(`Property: ${key}, Value: ${myObject[key]}`);
}
//[LOG]: "Property: key1, Value: value1" 
//[LOG]: "Property: key2, Value: value2" 

八. 函数

8.1 调用签名

可以给函数绑定一个属性

type DescriptionFuntion = {
    description: string
    (arg: number): boolean
}

function doSomething(fn: DescriptionFuntion) {
  console.log(fn.description + " return" + fn(6))
}

function fn(n: number) {
  console.log(n)
  return true
}
fn.description = "调用签名"

doSomething(fn)

//[LOG]: 6 
//[LOG]: "调用签名return true" 

8.2 构造签名

class Cls {
  name: string
  constructor(name: string) {
    this.name = name
  }
}

//方法1  字面量方式构造签名
function fn0(cls: new(name: string) => Cls): Cls {
   return new cls("aaa")
}
const cls0: Cls = fn0(Cls)
console.log(cls0)

function fnt<T>(cls: new(name: string) => T): T {
    return new cls("ttt")
}
const clst: Cls = fnt(Cls)
console.log(clst)

//方法2  接口对象字面量方式构造签名
function fn1(cls: {new (name: string): Cls}, name: string): Cls {
  return new cls(name)
}
const cls1: Cls = fn1(Cls, "bbb")
console.log(cls1)

//方法3 使用type或者interface
type ClsConstrutor = {
  new (name: string):Cls
}
function fn2(cls: ClsConstrutor): Cls {
  return new cls("ccc")
}

九.泛型

9.1 类型限制

//泛型T必须要有一个length属性
function longest<T extends {length: number}> (a: T, b: T) {
  return a.length > b.length ? a : b 
}

9.2 指定类型参数

function combine<T>(arr1: T[], arr2: T[]): T[] {
  return arr1.concat(arr2)
}
combine([1, 2, 3], [4, 5, 6])

// 报错了, 因为类型推断为number[]
// combine([1, 2, 3], ["a", "b", "c"])

// 如果你非得乱搞,那需要这样做, 声明数组的类型
let arr = combine<number | string> ([1, 2, 3], ["a", "b", "c"])
console.log(arr)//[LOG]: [1, 2, 3, "a", "b", "c"] 

9.3 泛型约束

interface haveLength {
    length: number
}
// 传入的参数需要有length属性
function use<T extends haveLength>(args: T) {
    console.log(args.length)
}
use("123")//[LOG]: 3

9.4 泛型约束中使用类型参数

function getProperties<Type, Key extends keyof Type>(t: Type, k: Key) {
    return t[k]
}
let obj = {
    a: 1,
    b: 2
}
let ret1 = getProperties(obj, "a")
console.log(ret1)//[LOG]: 1 

//let ret2 = getProperties(obj, "c")//报错, 没有这个key

十. This关键字

  • this的指向问题
    在 TypeScript 中,你可以在函数参数中使用 this 参数,这允许你显式地指定函数的调用方。通常,在函数内部,this 关键字用于引用当前对象,但对于一些情况,尤其是在回调函数或异步代码中,JavaScript 的默认行为可能导致 this 的值不是你期望的对象。

  • this和箭头函数, 注意:this在冒号前面.如果this在冒号后面,this就是指向调用方

class MyClass {
    name = "MyClass"
    getName() {
        return this.name
    }
    getConstName = () => {
        return this.name
    }
    getThisName(this: MyClass) {
        return this.name
    }
}

//没问题
let cls = new MyClass()
console.log(cls.getName())//[LOG]: "MyClass" 

//换个方式就有问题了
//getName获取到的是cls1的, 而不是MyClass的
let cls1 = {
    name: "cls1Name",
    getName: cls.getName//这是一个方法
}
console.log(cls1.getName())//[LOG]: "cls1Name" 


//怎么强行输出MyClass呢.
//1.使用=>, 把方法改成函数
let cls2 = {
    name: "cls2Name",
    getName: cls.getConstName//这是一个方法
}
console.log(cls2.getName())//[LOG]: "MyClass" 
//2.使用this关键字
let cls3 = {
    name: "cls3Name",
    getName: cls.getThisName
} 
console.log(cls3.getName())//报错, 直接不让cls3使用自己的name,只能使用MyClss的name

F

  1. type和interface的区别
    基本相同, 但是interface更容易扩展
//type后面跟个=
type Cls0 = {
  a: number
}
let a0: Cls0 = {a: 10}
//使用&符号type增加扩展
type Cls1 = Cls0 & {
  b: number
}
let a1: Cls1 = {a: 10, b: 20}
console.log(a1)


//interface后面没有=
interface Bill{ 
  a: number
}
let b0: Bill = {a: 10}
// 使用extend增加扩展
interface Bill1 extends Bill {
  b: number
}
let b1: Bill1 = {a: 10, b: 20}
console.log(b1)


//使用extend给type增加扩展  0.0
interface Cls2 extends Cls0 {
  c: number
}
let c: Cls2 = {a: 10, c: 30}
console.log(c)


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