先把前两天学习的基础的数据类型记录一下
数据类型
// 先可以在空文件夹中tsc init 然后生成tsconfig.json里面的outDir改为./js
// 然后在vscode中 点击上方终端 运行任务 监视TS就可以在修改此ts文件时自动生成对应的js文件
// 布尔类型 :后面的叫做 **类型注解**(Type Annotation)!
var flag:boolean = true
flag = false
flag = 20 > 30
// 数字类型 ts不区分int和float(double)类型,并且因为es6增加二进制和八进制的表示方法,ts也增加了二、八、十六进制的表示
var num:number = 123 //十进制
num = 12.3
num = 0b110 //二进制
num = 0o555 //八进制
num = 0xf23 //十六进制
// 字符串类型 单双引号都可以 最好使用"" 同js语法一样可以直接使用模板字符串
var str:string = '123'
console.log(str)
// 数组类型
// 第一种
var arr:number[] = [1,1,2,3,4,5]
var arr1:string[] = ['js','ts']
arr.push('c++') //报错
// 第二种
let arr2:Array<number> = [11,22,33]
let arr3:Array<string> = ['js','ts']
//对象类型
let obj:object = { name :'a' }
let obj1:{name:string} = {name :'b'}
// 元组类型 tuple类型中可以存放不同的数据类型,取出来的某一项也是有自己明确的类型的
// 在函数的返回值中是使用元祖类型最多的地方
let arr4:[string,number,boolean] = ['ts',123,true]
// 枚举类型
enum Flag {success=1,error=-1}
var f:Flag = Flag.success
console.log(f)
console.log(Flag.error)
enum Color {res,blue,orange}
var c:Color = Color.orange
console.log(c) //output:2 -- 对应的索引值
// 但是如果blue=5,那么打印orange则输出6
// any类型
var oBox:any = document.getElementById('box')
oBox.style.color = 'red'
// null & undefined 其他(never类型)数据类型的子类型
// var aa:number
// console.log(aa)//输出:undefined 但是报错
var aa:undefined
console.log(aa)//输出:undefined 但是不报错
// 但可以指定 var aa:number | undefined 则允许aa出现undefined
// null 同理
// void类型:ts中的viod表示没有没有任何类型,一般用于定义方法且方法没有返回值
//es5 语法
// function run(){
// console.log('run')
// }
// run()
function run():void{
console.log('run')
}
//指定了返回值类型为number
function run1():number{
return 123
}
run()
run1()
// never类型
var aaa:never
aaa = (()=>{
throw new Error('error')
})()
//unknown类型 与any类型相似但上面的任何操作都是不合法的
let id:any = '123'
id = 123
console.log(id.length)//这样是不会报错的
let _id:unknown = '123'
id = 123//这样是不会报错的
console.log(id.length)//这样是会报错的
//如果一定要使用的话 unknown类型必须要进行类型缩小 例如
if(typeof _id === 'string'){//这个在官方叫做类型缩小
console.log(id.length)//这样是不会报错的
}
总结:
ts中的数据类型和js类似,但是多出几个。
一共有:
布尔类型
boolean
数字类型
number
字符串类型
string
数组类型
any[]
Array
对象类型
object
{ name: string, age: number }
元组(tuple)类型
枚举类型
任意(any)类型
viod类型
null & undefined类型
symbol类型
never类型
unknown类型
最后在声明变量的时候少使用any类型,据说有的公司是开发规范中直接禁止使用any类型,不知道是真是假。
然后,基本的,背就完事了。
在声明一个变量的时候,如果对其直接进行赋值,那么根据类型推导会直接对变量进行类型注解。
let a = 'a'
// 变量a会默认为 let a:string = 'a'
a = 1 //报错
如果用let来声明进行类型推导,那么推导出来的是通用类型,用const进行声明,则是推导的字面量类型。
let a = 'a'
// 变量a会默认为 let a:string = 'a'
const b = 'hello'
// const b:hello = 'hello'
联合类型和交叉类型
ts中类型系统允许使用多种运算符从现有类型中构建新类型
联合类型 union type
联合类型是由两个或多个其他类型组成的类型。
表示该变量可以是这些类型中的任何一种
联合类型中的每一个类型被称之为联合成员
let foo:string|number = '123'
foo = 123
//但是不能直接使用foo.length ,必须使用类型缩小
function logID(id: number | string){
console.log('id is :', id)
}
交叉类型表示两种或多种类型要同时满足
type foo = string & number //实际上是never
interface IMan {
name:string
age:number
}
interface Icoder {
coding: () => viod
name:string
}
//同时满足两个接口的属性
const me: IMan & Icoder {
name:'aa',
age:30,
coding:function(){
console.log('1')
}
}
类型别名
type my_type = number
const age:my_type = 18
type IDtype = number | string
let id:IDtype = 1
id = '123'
在ts中类型别名和接口声明(比如对象)容易搞混
但是其中的特性有不同,在定义对象类型时,大部分时候可以任意选择使用,接口的几乎所有特性都可以再type中使用
1.type范围更广泛,接口声明只能来声明对象。
2.在声明对象时候,interface可以多次声明,而type不允许两个相同名称的别名同时存在。
3.interface支持继承,可以被类实现。
类型断言: as
//获取DOM元素
const imgEl = document.querySelector("img")
//此时 imgEl 实际上是一个 HTMLImageElement | null 的联合类型,可以直接imgEl.src imgEl.alt来获取对应的属性
const imgEl = document.querySelector(".img")
//此时 imgEl 实际上是一个 Element | null 的联合类型 就拿不到src alt
const imgEl = document.querySelector(".img") as HTMLImageElement
//此时使用类型断言,可以直接imgEl.src imgEl.alt来获取对应的属性
断言只能成更加具体或者不太具体(一般指的any/unknown)的类型,比如
const a:number = 1
const a1 = a as string //报错
const b:number = 1
const b1 = b as any //(不太具体)
const b2 = b1 as string (//具体)
函数
然后今天学习一下函数
// 1.函数的定义
// ts 函数的声明方法
function run(): string {
return '123'
}
// 如果不写:number、那么相当于没有指定函数的返回值类型,但会进行类型推断,是fnNum 被推断为number类型
let fnNum = function (): number {
return 123
}
// 匿名函数
let fnRun = function (): number {
return 123
}
// ts中 定义方法传参
function getInfo(name: string, age: number): string {
return `${name}+${age}`
}
function getInfo1(name: string, age: number): void {
console.log(`${name}+${age}`)
}
// 可选参数
// es5里面方法的实参和形参可以不一样,但是ts中必须一致,如果不一致,就需要配置可选参数
function getInfo2(name: string, age?: number): string {
if (age) {
return `${name}+${age}`
} else {
return `${name}+年龄保密`
}
}
getInfo2('zhagnsan')
getInfo2('zhangsan', 10)
// 可选参数必须写在参数的最后面
// 下面这个写法就是错误的
// function getInfo2(name?: string, age: number): string {
// return `${name}+${age}`
// }
// 默认参数
function getInfo3(name: string, age: number = 20): string {
if (age) {
return `${name}+${age}`
} else {
return `${name}+年龄保密`
}
}
getInfo3('zhagnsan')
getInfo3('zhangsan', 10)
// 剩余参数
function sum(a: number, b: number, c: number, d: number): number {
return a + b + c + d;
}
sum(1, 2, 3, 4)
function sum1(a: number, ...res: number[]): number {
let sum = a;
console.log(sum)
for (let i = 0; i < res.length; i++) {
sum += res[i]
}
return sum
}
sum1(1, 2, 3, 4)
// 实际就是es6展开运算符的应用
// ts函数的重载
// ts为了兼容es5和es6 重载的写法和java中有区别
function css(name:string):string;
function css(age:number):number;
function css(str:any):any{
if(typeof str === 'string'){
return str + '123'
}else{
return str
}
}
css('zhangsan')
// 走第一个
css(20)
// 走第二个
// css(true) 就报错
// 所以也就是同样的函数 传不同的参数 执行不同的内容
//转载一个详细的重载讲解,link: https://www.jianshu.com/p/b11e24dec350
// 上边是声明
function add (arg1: string, arg2: string): string
function add (arg1: number, arg2: number): number
// 因为我们在下边有具体函数的实现,所以这里并不需要添加 declare 关键字
// 下边是实现
function add (arg1: string | number, arg2: string | number) {
// 在实现上我们要注意严格判断两个参数的类型是否相等,而不能简单的写一个 arg1 + arg2
if (typeof arg1 === 'string' && typeof arg2 === 'string') {
return arg1 + arg2
} else if (typeof arg1 === 'number' && typeof arg2 === 'number') {
return arg1 + arg2
}
}