当前位置:网站首页>ts和js区别
ts和js区别
2022-07-02 06:23:00 【江河i】
ts和js区别
阮一峰ts官网http://ts.xcatliu.com/introduction/what-is-typescript.html
ts官网https://www.tslang.cn/docs/home.html
typescript
typescript 是javascript类型的超集, 可以编译成纯javascript, ,可以跨浏览器,跨平台运行
如果你很在乎开发速度,快速迭代,那么建议你继续用 JavaScript。如果你需要高稳定性,那么建议你使用 TypeScript。
数据类型
js基本数据类型:number string boolean undefined null symbol
js的引用数据类型: Object array function
ts定义数据类型
编译:tsc home.ts
运行:node home.js
直接运行ts文件解说https://yunan.blog.csdn.net/article/details/108339140
运行 ts-node 文件名.ts
- 基本数据类型
let 变量名:数据类型 = 值
// 数据类型定义
let num:number = 100;
let str:string = 'hello'
let flag:boolean = true;
let timer:undefined = undefined;
let obj:null = null;
默认情况下null和undefined是所有类型的子类型 ; 就是说你可以把 null和undefined赋值给任何类型的变量
- 任意类型
使用 any 关键字 定义任意类型
let 变量名:any = value;
// 后期可以随便进行更改
例子 let str:any=100;
console.log(str);//100
- 函数的定义方式
- 函数的参数类型定义
function f(str:string, ...){
}
function fn(str:number){
console.log(fn);
}
fn(100)
- 函数返回值的定义
// 函数存在返回值
function 函数名(参数名:参数类型):返回值的类型{
return value; // value 比如符合你定义的类型
}
function sum(a:number,b:number):number{
return a+b;
}
console.log(sum(1,2));//3
// 函数没有返回值 使用void 关键字
function 函数名(参数名:参数类型):viod{
// 函数不需要返回值
}
function red(a,d):void{
console.log(a);
}
red(100,200)
// 如果函数的返回值是一个对象
function f(n:string, a:number):{
name:string,age:number}{
return {
name:n, age:a}
}
function f(n:string, a:number):{
name:string,age:number}{
return {
name:n, age:a}
}
console.log(f("hello",100));//{ name: 'hello', age: 100 }
- ts的类型推论
TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论
let x = 100; // 这种情况下 ts 就会使用类型推论
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:
- 隐式任意类型
let str; // 通过类型推论 推断为 任意类型
str = 'hello';
str = 100;
联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种。 使用 | 符号
let 变量名: 数据类型1 | 数据类型2 | ... = value ;// value 可以是 类型的任意一个; 后期可以更改为定义的类型中任意一个
let arr:number|string=100
arr="hello"
console.log(arr);//hello
- 定义数组
let 变量名:[number, string] = [1, '3'];
let 变量名:[number | string, string] = [1, '3'];
let str:[number | string, string] = [1, "3"];
console.log(str);//[1, "3"];
对象的类型-接口
在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。
//定义了一个接口 Person,接口名字首字母大写
interface Person {
name: string;
age: number;
}
//接着定义了一个变量 tom,它的类型是 Person
let tom: Person = {
name: 'Tom',
age: 25
};
console.log(tom.name);//Tom
- 可选属性
定义可选属性 通过 ? : 如果有一些属性是可有可无,可以定义为可选属性,通过 在属性名后边添加 ? 实现
interface Person{
name:string;
age:number;
sex?:string;
hariColor?:string
}
let stu:Person = {
name:'hello',
age:18,
sex:'nv',
hariColor:'123984'
}
console.log(stu);
- 定义任意属性(也是可有可无)
[propName:数据类型] :any 使用 [propName: string] 定义了任意属性取 string 类型的值。
interface Person {
name: string;
age?: number;//可选属性
[propName: string]: any;//任意类型
}
let tom: Person = {
name: 'Tom',
gender: 'male'//可以是任意类型
};
- 定义只读属性
通过 readonly 关键字
只读: 只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候:
interface Person {
readonly name:string;
age:number
}
//只读 在该环节生效的
let stu1:Person = {
name:'张三',
age:19
}
//console.log(stu.name);
stu1.name="李四"//只读属性不允许修改
函数返回值 ,返回值是对象
interface Person {
name: string;
age: number
}
//函数返回值 ,返回值是对象
function Stu1(a:Person):{
name:string, age:number}{
let newStu = {
name:'张三', age:100}
if(a.name){
newStu.name = a.name;
}
if(a.age){
newStu.age = a.age;
}
return newStu
}
var res = Stu1({
name:'李四', age:18})
console.log(res);//{name:'李四', age:18}
数组的类型
- 「类型 + 方括号」表示法
let str1:number[]=[1,3,4,5];
- 元组: 限定数组中每个元素的类型 , 同时也限定了数组中元素的个数;
(元组不是数组,只是刚好符合数组的规范)
let arr2:[number, string] = [1, 'hello']
- 通过 数组的泛型 Array<数据类型>
let arr3:Array<number> = [21,4,45,23]
let arr4:Array<string> = ['ajds']
- 通过接口定义数组 [index:number] 限定的是数组索引值的类型, 后边是限定数组中元素的类型
interface a{
// [index:number]:number
[index:number]:string
}
// let arr5:a = [1,4,5,6]
let arr5:a = ['234', '345', '35432']
允许数组中出现任意值:any[]
let arr6:any[] = [23, '345', {
name:'zadf'}]
函数的类型
函数声明式
function fun(a:number, b:number){
}
函数表达式
let fun2 = function(a:number, b:number){
}
// 限定返回值
function fun(a:number):number{
//第二个number就是限定的返回值(也叫输出)
return a + 100;
}
console.log(fun(100));//200
书写函数的完整格式
// 针对的是函数表达式的方式
// 定义函数时的变量名可以不同,但是数据类型必须一致
// 区分 => 和 es6 的箭头函数 箭头 number这里是规定输出值的类型,不是箭头函数
let fun2:(x:number, y:number) => number = function(a:number, b:number):number{
return a + b; //返回值类型
}
console.log(fun2(10,20));//30
注意:箭头函数右边的number是输出类型,
右边括号外的number是返回值类型
箭头如果实在函数表达式中(就是声明函数时使用的),意味着是指定函数返回值的类型,除此以外代表都是箭头函数
let fun2:(x:number, y:number) => string = (a:number, b:number):string=>{
//第二个箭头才是箭头函数
return (a + b).toString();
}
console.log(fun2(10,20));//30
- 可选参数
function f(x?:number){
}
- 默认值参数
function f(x:number, y = 100 ){
}
- 剩余参数 我们可能不确定参数个数: 这个时候可以使用剩余参数 (rest参数)
function fun(a:number, b:number, ...args:number[]){
console.log(a, b, args); //1 3 [ 4, 6, 8 ]
}
fun(1, 3, 4, 6, 8)
函数重载
函数重载: 同名的函数根据参数类型和个数的不同实现不同的功能
// 定义函数重载类型
function 函数名(参数:数据类型1):返回值类型1;
function 函数名(参数:数据类型2):返回值类型2;
// 函数的实现的定义
function 函数名(参数:数据类型1 | 数据类型2):数据类型1 | 数据类型2{
// 逻辑处理
}
function 函数名(参数:any):any{
// 逻辑处理
}
具体实现:
x: {
suit: string; card: number; }[] 传入的参数是一个json对象, 形如:
[
{
suit:'',
card:1
},
{
suit:'',
card:1
},
{
suit:'',
card:1
},
]
//1 定义重载函数的类型 : 定义的是函数类型
function pickCard(x: {
suit: string; card: number; }[]): number;
// let a = 100;//这里不能写会报错
function pickCard(x: number): {
suit: string; card: number; };
// 2 定义函数 !!!!!!!!!!!!!!!! 函数类型定义和函数定义之间不能 存在任何代码
function pickCard(x:any):any{
if(typeof x == 'object'){
return 100;
}else if(typeof x == 'number'){
return {
suit:'hello', card:100}
}
}
console.log(pickCard(100));//{suit:'hello', card:100}
console.log(pickCard([{
suit:'213423', card:100}]));//100
枚举
定于枚举类型: 使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript支持数字的和基于字符串的枚举。
// 通过关键字 enum 定义枚举类型
// 一旦定义枚举类型 : 数字类型的枚举,会存在默认值,默认值从0开始 ; 默认值会依次递增 enum Per{
// 随意自定义 ; 自定义的是常量的名字,而没有给常量赋值,常量的默认是从0开始的
A,//默认A=0
b,//B=1
}
/*Per[1] 这是通过枚举类型的值 获取枚举类型的名字 []中的数字是 枚举类型的值; 而不是索引值 */
console.log(Per[1]);//b
// 可以手动指定枚举类型的值 enum E {
a, // 第一个枚举名没有指定值,则默认是从0开始
b,
d = 12, // 指定了值,则使用指定的值
c, // 没有指定值,会从上一个枚举值自动递增
f = 16
}
//console.log(E[0], E[12],E[13]);//a b c
//console.log(E.a, E.b, E.c);//0 1 13
console.log(E['a'], E['b'], E.c);//0 1 13
// 访问枚举类型有两种方式:
// 第一种是通过枚举的值访问枚举类型名 枚举变量名[值];
// 第二种是通过枚举类型名访问枚举类型值 枚举变量名.枚举常量名 或者 枚举变量名['枚举常量名'] ;
泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,
而在使用的时候再指定类型的一种特性。
泛型: <自定义的的值> 代表数据类型,后期由你传入的类型决定 比如: <T> <M> <A>
function f<M>(arg:M):M{
//第一个m是泛型 第二个是传入值的类型 第三个是返回值类型
return arg;
}
console.log(f<string>('hello'));//hello
类型断言(Type Assertion)可以用来手动指定一个值的类型
语法: 值 as 类型
// 接口约束 类型断言
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
// 类型断言 : 我知道自己在干嘛,所以不需要ts帮我们进行类型判断
function getName(animal: Cat | Fish) {
//return animal.name;//HEISE
// animal.run();报错
//animal.swim();报错
// 类型断言 (我知道自己要去用Fish接口)
(animal as Fish).swim()
}
let str = getName({
name: 'HEISE', swim: function () {
console.log("函数")
}
})
console.log(str);//函数
泛型约束
// 泛型约束
//在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:
function test<T>(a: T[]):T{
console.log(a.length);
// return a.length; // 报错: 泛型约束(因为这个时候你还不知道返回值是什么类型)
return a[2]
}
console.log(
test<number>([1,3,54,6]));// 4 54
类
es6中类的用法1
使用 class 定义类,使用 constructor 定义构造函数。
通过 new 生成新实例的时候,会自动调用构造函数。
class Animal {
//实例对象属性
name;
//构造器constructor方法是类的默认方法,定义私有的属性
constructor(name) {
this.name = name;
}
//公有的方法
sayHi() {
}
//静态方法
static say() {
}
//class的getter和setter
get name() {
return 'Jack';
}
set name(value) {
console.log('setter1: ' + value);
}
}
//Vue的双向数据绑定的原理,数据劫持,(object.definedProper),就是通过get和set方法实现,只能拦截一次
TypeScript 中类的用法
class Person {
name:string;
constructor(name:string='hello') {
//hello是默认值
this.name=name
}
}
let a = new Person();//如果这里传值,就会使用
console.log(a);//Person { name: 'hello' }
console.log(a.name); // Jack
public private 和 protected
TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected。
public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
class Animal {
public name:any;//公有的属性
public constructor(name:any) {
this.name = name;
}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
console.log(a.name); // Tom
private修饰的属性或方法是私有的,只能在类的内部访问
class Animal {
private name:any;
constructor(name:any) {
this.name = name;
}
sayHi() {
return `My name is ${
this.name}`;
}
}
let a = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
使用 private (私有)修饰的属性或方法,在子类中也是不允许访问的:
class Animal {
private name:any;
public constructor(name:any) {
this.name = name;
}
}
class Cat extends Animal {
constructor(name:any) {
super(name);
console.log(this.name);
}
}
换为protected 受保护的就不会报错了
class Animal {
protected name:any;
public constructor(name:any) {
this.name = name;
}
}
class Cat extends Animal {
constructor(name:any) {
super(name);
console.log(this.name);
}
}
只读属性的初始化操作,要么在声明的时候进行,要么在构造器中进行
class Animal {
readonly name;
public constructor(name) {
this.name = name;
}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
//报错Cannot assign to 'name' because it is a read-only property.
类型别名
类型别名用来给一个类型起个新名字。
类型别名有时和接口很像,但是可以用于原始值,联合类型,元祖以及其它任何需要手写的类型
通过type 关键字定义类型别名
type Name = string;//给string起了个别名name
type NameResolver = () => string;//类型别名还可以是一个函数(定义一个函数,函数的返回值是string类型,这里的)
箭头如果实在函数表达式中(就是声明函数时使用的),意味着是指定函数返回值的类型,除此以外代表都是箭头函数
type NameOrResolver = Name | NameResolver;//综合类型
function getName(n: NameOrResolver): Name {
if (typeof n === 'string') {
return n;
} else {
return n();
}
}
console.log(getName("string"字符串)//字符串的情况
let res=getName(function(){
//else的情况
return 'hello'
})
console.log(res)//hello
上例中,我们使用 type 创建类型别名。
类型别名常用于联合类型。
声明文件
declare var num:number;//声明一个变量
declare function jQuery(selector: string): any;//声明了一个方法
num = 100;
jQuery('#app')
声明文件: 扩展名时 .d.ts ; 格式: 自定义文件名.d.ts
ts 会自动查找声明文件
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
我们通常这样获取一个 id 是 foo 的元素:
$('#foo');
// or
jQuery('#foo');
但是在 ts 中,编译器并不知道 $ 或 jQuery 是什么东西1:
jQuery('#foo');
// ERROR: Cannot find name 'jQuery'.
这时,我们需要使用 declare var 来定义它的类型2:
declare var jQuery: (selector: string) => any;
jQuery('#foo');
上例中,declare var 并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型,仅仅会用于编译时的检查,在编译结果中会被删除。它编译结果是:
jQuery('#foo');
边栏推荐
- DeprecationWarning: .ix is deprecated. Please use.loc for label based indexing or.iloc for positi
- Sentinel rules persist to Nacos
- IDEA公布全新默认UI,太清爽了(内含申请链接)
- selenium+msedgedriver+edge浏览器安装驱动的坑
- 2020-9-23 QT的定时器Qtimer类的使用。
- Redis——缓存击穿、穿透、雪崩
- Code skills - Controller Parameter annotation @requestparam
- (第一百篇BLOG)写于博士二年级结束-20200818
- 华为MindSpore开源实习机试题
- Latex在VSCODE中编译中文,使用中文路径问题解决
猜你喜欢
unittest. Texttestrunner does not generate TXT test reports
js中正则表达式的使用
Latex在VSCODE中编译中文,使用中文路径问题解决
Redis——缓存击穿、穿透、雪崩
Présence d'une panne de courant anormale; Problème de gestion de la fsck d'exécution résolu
Win10桌面图标没有办法拖动(可以选中可以打开可以删除新建等操作但是不能拖动)
VSCODE 安装LATEX环境,参数配置,常见问题解决
Idea announced a new default UI, which is too refreshing (including the application link)
Shardingsphere JDBC
Redis - cluster data distribution algorithm & hash slot
随机推荐
Win10:添加或者删除开机启动项,在开机启动项中添加在用户自定义的启动文件
Sublime Text 配置php编译环境
FE - 微信小程序 - 蓝牙 BLE 开发调研与使用
TensorRT的数据格式定义详解
Win电脑截图黑屏解决办法
Detailed definition of tensorrt data format
压力测试修改解决方案
Présence d'une panne de courant anormale; Problème de gestion de la fsck d'exécution résolu
看完有用的blog
20210306 reprint how to make TextEdit have background pictures
Apt command reports certificate error certificate verification failed: the certificate is not trusted
由於不正常斷電導致的unexpected inconsistency;RUN fsck MANUALLY問題已解决
如何调试微信内置浏览器应用(企业号、公众号、订阅号)
Name six schemes to realize delayed messages at one go
Codeforces Round #797 (Div. 3) A—E
计算属性普通函数写法 和 set get 写法
QQ email cannot receive the email sent by Jenkins using email extension after construction (timestamp or auth...)
Render minecraft scenes into real scenes using NVIDIA GPU
Deployment API_ automation_ Problems encountered during test
pytest(2) mark功能