一、ts使用前的必备工序二、正式开启ts学习之旅ts数据类型数值型字符型布尔型undefinednull数组类型 有2种写法二维数组元组类型 Tuple枚举类型 enumany类型void类型never类型object类型Symbol类型bigint类型Function 函数类型| 或者类型类型断言变量声明重载对象接口函数接口所以接口当中不能实现重载类类型和类接口类类型接口类实现接口难度上升 如何给类类型参数接口的继承
小编碎碎念:TypeScript和Java真的很像啊哈哈……
多看多练多看多练多练多练多练多练......*n
后面出的文章会补上ts更深一点的内容,让我先鼓起勇气学学......
一、ts使用前的必备工序
之前已经安装过ts(npm i typescript -g),所以直接输入
tsc --init
生成tsconfig.json文件
手动配置好tsconfig.json文件,我选择的是ES6版本的配置,可以直接复制进自己的tsconfig.json文件里
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "ES6", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "ES6", /* Specify what module code is generated. */
"rootDir": "./ts", /* Specify the root folder within your source files. */
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
"declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "./js", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}
然后新建一个ts文件夹和一个js文件夹
新建一个index.html文件
ts文件夹里,新建一个Main.ts文件
ctrl+~打开终端,输入
tsc -w
开启监视并转换,意思就是现在你在ts文件夹创建的ts文件都会在js文件夹里自动转换为js
打开index.html
输入! 回车生成html默认代码
敲出script标签,添加type属性,值为module,这是ES6的模块化开发引入方式,告诉浏览器,脚本应该被当作模块module来对待,并且自动开启严格模式,会在所有html代码加载完后才最后加载
通过import引入js文件,是js不是ts哈,注意一下
二、正式开启ts学习之旅
怎么说呢,目前为止(2023年),市面上不少公司还是要求会TypeScript的,好好学哈
打开TypeScript中文网,查看
TypeScript中文网链接:
https://www.tslang.cn/
点开文档
ts数据类型
ts是一种强类型语言,所以我们在使用变量时必须标明变量类型
数值型
var a:number=1;
就代表,如果把a修改为字符型,或者布尔型,a这里都会报错,必须要求是数值型
还有一种也是数值型
var b:Number=2;
这两种有什么不同呢,就是下面兼容对象类型,如果上面使用对象类型会报错,下面就可以使用对象类型
数值型支持整数,小数,负数,十六进制,十进制,八进制,二进制,科学计数法
字符型
var a:string="a";
var b:String="b";
同理,下面是兼容对象类型的
a='a';
a="a";
a=`a`;//ES6新出的反引号字符串模块
布尔型
var a:boolean="true";
var b:Boolean="false";
undefined
var a:undefined=undefined;
a只能等于undefined
这个用在哪呢,用在a有可能是一种类型或者undefined型时
var a:number|undefined;
这就代表a可能是number或者undefined类型
null
null常用于切断对象的引用关系,就是给对象变量赋值为null,就会释放相应堆内存,避免内存溢出,提升程序性能
var a:null=null;
a只能等于null
也可以用于或者
var o:object|null={a:1,b:2};
o=null;
数组类型 有2种写法
第一种,尖括号里写数组的元素类型
var arr:Array<number>=[1,2,3];//建议使用这种,后面尖括号是种泛型,后面会讲什么是泛型
第二种,这也是表示这是一个数值型数组
var arr:number[]=[1,2,3];
这样写就代表,数组元素既可以是数值型也可以是字符型
var arr:Array<number|string>=["a",1,"b"];
这样写也可以,但比较麻烦
var arr:number[]|string[]=["a",1,"b"];
或者
var arr:(number|string)[]=["a",1,"b"];
二维数组
注意二维数组的ts写法略有不同
var arr:Array<Array<number>>=[[1,2,3],[4,5,6]];
var arr:number[][]=[[1,2,3],[4,5,6]];
元组类型 Tuple
元组和数组有点相似
var list:[number,string,number,string]=[1,"a",3,"b"];
list[1]=3;//会报错
list[1]="a";
注意list[1]是第1项,不是第0项哈,类型是string
元组其实就是把元素的类型规定死了
会将数据中每个下标对应的类型都严格标识
枚举类型 enum
enum COLOR{RED,GREEN,BLUE};
console.log(COLOR.RED);//0
枚举没有设置初始值时,默认从0开始
enum COLOR{RED=-1,GREEN,BLUE};
console.log(COLOR.RED);//-1
console.log(COLOR.GREEN);//0
给了初始值,就从初始值开始递增
例子1:
enum COLOR{RED,GREEN=5,BLUE};//0 5 6
例子2:可以给字符类型,但是如果某一个设置了字符型的值,其后面的类型不能再使用数值索引,而是给固定的值
enum COLOR{RED="red",GREEN=2,BLUE="blue"};//red 2 blue
console.log(COLOR.RED);
console.log(COLOR.GREEN);
console.log(COLOR.BLUE);
COLOR类型就是上面的枚举类型,所以a变量只能有上面的三个值域
var a:COLOR=COLR.RED;
console.log(COLOR[a]);
any类型
ts中强烈不建议使用any,都写any了,还用什么ts哈哈,所以迫不得已的情况下再使用any,比如紧急赶项目,比如项目很小,开发时间很短,就可以用用
var a:any=3
万物皆可any
在服务端传给前端的数据可以使用any,因为有可能是JSON字符串,那么转换成对象的过程中出现的数据类型就可以使用any
相应的,前端传给服务端的数据也可以使用any类型
void类型
var a:void;
a=undefined;//a被定义void类型,就只能是undefined
所以void和any是相反的类型,它表示没有返回任何类型
void主要用于函数的返回值,不会在定义变量时使用
never类型
就是永远不会有,也是主要用于函数的返回
function fn():never{
throw new Error("aa");
}
就是这个函数,只要你执行这个函数,它就会给你抛出异常,那你觉得执行这个函数有正确的时候吗,不会
就是函数不会返回正确值,都会抛错
其实也不建议使用never类型,给的话也是error类型
object类型
var o:object={a:1,b:2};
var o1:Object={a:1,b:2};
o=new Object();
这两种写法一模一样,但我们基本不使用object类型
因为使用object不能添加,不能删除,因为object是个笼统的说法,只是说是个对象类型,但是具体有啥,不知道
所以一般不设置该类型
Symbol类型
var a:Symbol=Symbol("a");
bigint类型
这个只有在ES2020版本出现,如果要使用bigint需要在tsconfig.json把版本改成ES2020
Function 函数类型
注意首字母大写
Function 函数类型,函数的笼统类型,一般也不这样定义
var fn:Function=function(){
}
| 或者类型
就是可以组合多个类型
var a:number|string="a";
a=1;
类型断言
和正则的断言是两回事,不一样哈
就是多种类型都可以的情况下,我确定要1种类型的时候用
function fn(){
var div:HTMLDivElement|null=document.querySelector("div");
}
fn();
这里你看,获取到的既可能是HTMLElement类型,也可能啥也没有也就是null类型
所以使用类型断言,就在后面加上as HTMLDivElement
function fn(){
var div:HTMLDivElement|null=document.querySelector("div") as HTMLDivElement;
}
fn();
//断言还有第2种写法,这两种都可以
function fn(){
var div:HTMLDivElement|null=<HTMLDivElement>document.querySelector("div");
}
fn();
所以断言是非常"无赖"的,它说是就是,但用起来也是真的爽哈哈哈
所有数据类型讲完,接下来是
变量声明
变量声明时的数据类型表示你在使用该变量时所给的值,或者返回值不是该数据类型,ts就会报错,提示你改成正确的实值
重载
//重载
function getSums(a:number,b:number):number;
function getSums(a:string,b:string):string;
function getSums(a:number):number;
function getSums(a:string|number,b?:string|number):string|number{
if(typeof a==="string" && typeof b==="string"){
return a+b;
}else if(a==="number" && typeof b==="number"){
return a+b;
}else{
return a;
}
}
其实我们要定义的函数只有一个,却写了很多个,这就叫重载
可以看到使用这个函数时有四种传参方式
//重载案例
function setElement(elem:HTMLDivElement,arr:Array<number>,callback:()=>void):void;
function setElement(elem:HTMLDivElement,callback:()=>void):void;
function setElement(elem:HTMLDivElement,arr:Array<number>|Function,callback?:()=>void){
if(typeof arr==="function"){
callback=arr as ()=>void;
}
}
var div:HTMLDivElement=document.querySelector("div") as HTMLDivElement;
setElement(div,[1,2,3],function(){
})
setElement(div,function(){
})
对象接口
function fn(obj:{a:number,b:number}):void
{
obj.a=10;
}
fn({a:1,b:2})
接口内定义的属性可以在外面重新赋值,但是不能增加属性,会报错
interface Iobj{
a:number,
b:number,
c:number,
play:()=>void;
}
interface Iobj{
a:number;
b:number;
c:number;
play():void;
}
//这俩写法一样
var obj:Iobj={
a:1,
b:2,
c:3,
play():void{
console.log("a");
}
}
//这就叫接口
可选属性
这里问号冒号就是可选属性,c在调用时赋不赋值都可以,不会报错
interface Iobj{
a:number,
b:number,
c?:number,
play:()=>void;
}
readonly只读属性
interface Iobj{
a:number,
readonly b:number,
c:number,
play:()=>void;
}
var obj:Iobj={
a:1,
b:2,
c:3,
play():void{
console.log("a");
}
}
console.log(obj.b)
obj.b=10;//会报错
//有设置只读属性的属性,在接口实例化内不允许再次修改值,需要注意这点
只读数组
var arr:ReadonlyArray<number>=[1,2,3,4];
arr[0]=1;//会报错
额外属性
interface IObj{
a:number,
b:number,
[key:string]:number
}
var o:IObj={a:1,b:2};
o.d=3;
o.e=4;
//这样就能添加任意多个属性了
还有[index:number]索引值写法
interface IObj{
a:number,
b:number,
[key:string]:number,
[index:number]:number
}
var o:IObj={a:1,b:2};
o.d=3;
o[1]=10
上下不兼容问题
可以看到a是字符型,而下面key只有number型,所以要让key兼容string类型,就不会报错了
接口继承类,就可以使用类的属性和方法
interface IEvent extends Event{
[key:string]:any;
}
var target:EventTarget=new EventTarget();
target.addEventListener("change",changeHandler);
var evt:IEvent=new Event("change");
target.dispatchEvent(evt);
function changeHandler(e:Event):void{
}
这样我们就可以给IEvent添加任意key和值啦
evt.a=1
以上都叫对象接口,接下来我们来说函数接口
函数接口
var fn:(a:number,b:number)=>void=function(a:number,b:number):void{
}
fn(1,2);
interface IFn{
(a:number,b:number):void;
}
var fn:IFn=function(a,b){
}
fn(1,2);
//案例1 这个不是重载,这是覆盖
interface IFn{
(a:number,b:number):void;
(a:string,b:string):void;
}
var fn:IFn=function(a:number,b:number):void{//这里会报错
}
fn(1,2);
所以接口当中不能实现重载
函数断言
interface IFn{
(a:number,b:number):void;
a:number;
}
var fn:Ifn=function(a:number,b:number):void{
} as IFn;//因为函数不能先给属性,所以就先断言这个就是IFn类型,然后就可以给a属性了
var fn:IFn=<IFn>function(a:number,b:number):void{
}//这个是第二种写法,尖括号
fn.a=10;
//函数接口案例1 返回类型是自己这个IFn类型
interface IFn{
(a:number):IFn;
}
function fn(a:number){
console.log("a");
return fn;
}
var a:(b:number)=>number=fn(1);
var s:number=a(3);
console.log(s);
接口中不能写默认值参数
interface IFn{
(a:number,c:number=3);//这会报错
}
类类型和类接口
类类型接口
class Box{
a:number;
b:number;
constructor(a:number,b:number){
this.a=a;//没写这俩会报错
this.b=b;//没写这俩会报错
}
}
为啥报错呢,因为类中属性必须有初始值设定,可以在定义时赋值初始值,也可以在constructor构造函数中设定初始值
如果设置?:可选属性时,不需要设置初始值,就是不给不会报错
静态属性不需要给初始值
//只有实例化属性才需要给初始值
class Box{
a:number;
b:number;
c?:number;
static ab:number;
constructor(a:number,b:number){
this.a=a;
this.b=b;
}
play(a:number,b:number):number{
return a+b;
}
}
//ts类和构造函数 案例1
class Box{
a:number;
b:number;
constructor(a:number,b:number){
this.a=a;
this.b=b;
console.log(a,b);
}
}
var b=new Box(1,2);//打印1 2
类型就是你可以调用这个类的属性和方法,继承也是类似的原理,只不过是调用父亲的
那么类如何写接口呢,以上面的类为例
interface IBox{
a:number;
b:number;
c?:number;
play(a:number,b:number):number;
}
类的接口并不能写constructor构造函数,因为其返回的类型不是IBox,写any也会报错,说明返回的类型和类的类型不同
所以这就是一个类类型的接口
类实现接口
interface IA{
a:number;
}
interface IB{
b:number;
}
interface IC{
update():void;
}
// implements 表示实现 IA接口
class Box implements IA{
a:number=1;
constructor(){
}
play():void{
console.log("play");
}
}
//当b是Box类类型的实例化,是可以调用a属性和play()方法的
var b:Box=new Box();
console.log(b.a);
b.play();
//当b是IA接口类型的实例化,就不能调用play()方法了,因为IA接口里没有这个方法
var b:IA=new Box();
console.log(b.a);
b.play();//会报错 因为IA没有IA
//这里的确是实例化Box了,但是b是IA类型,即使有play方法也不认为能调用,因为IA接口里没有play方法
这个constructor构造函数,功能主要是
1.new 类的时候传参默认就是传给constructor函数
2.继承的时候,子类super()必须写在子类constructor函数第一句,这个表示自动执行父亲的constructor函数,所以还得注意父亲的constructor函数是否有参数
interface IA{
a:number;
}
interface IB{
b:number;
}
interface IC{
update():void;
}
// 可以让类实现多个接口
class Box implements IA,IB,IC{
a:number=1;
b:number=2;
constructor(){
}
update(): void {
console.log("aa");
}
}
// var b:Box=new Box();
// var b:IA=new Box();
// var b:IB=new Box();
// var b:IC=new Box();//因为b同时实现这些接口,所以b都是这些类型
class Ball implements IC{//因为Ball是实现IC,所以IC里面有什么,Ball就必须有什么
constructor(){
}
update(): void {
console.log("bb");
}
}
//这个表示把IC类型的对象放进数组arr中
var arr:Array<IC>=[];
arr.push(new Box());
arr.push(new Ball());//这个也可以,因为它也实现了IC类型
arr.forEach((item:IC)=>{
item.update();
})//打印
//aa
//bb
看这张图↓ 意思就是子类实例化时,它所继承的超类,父类的属性和方法它都可以调用
看下图↓ 它俩有共同接口IC,都具备IC里的属性和方法
在类的继承中↓
在接口中,类1和类2实例化对象是没有继承关系的,也就是类1实例化不属于类2
难度上升 如何给类类型参数
当我需要给个参数,而参数类型是个实例化对象时怎么给
方法是:新建一个类类型接口,在里面写new实例化
因为Box不是Box类型啊,new Box(1,2)才是Box类型
//案例
interface IUpdate{
update():void;
}
class Box implements IUpdate{
constructor(a:number,b:number){
}
update():void{
console.log("aa")
}
}
interface IBox{
new (a:number,b:number):IUpdate;
}
function createBox(className:IBox):IUpdate
{
var b:IUpdate:new className(1,2);
return b;
}
create(Box);
//这里Box是一个实例化对象,而且被放进create方法的实参
//因为IBox把它new了,它实例化了,就可以作为实参了,因为类型不可以作为实参,而应该是实例化的对象作为实参
//所以这里顺序是,我的create函数需要一个实例化实参,所以我写了
class Box,但是这个没有实例化,我也不该在参数那里写new Box(),所以我写了个接口IBox,来帮助Box实例化,然后,我就可以在调用createBox时,放入IBox类型的实参,因为IBox接口的作用就是把类class Box实例化一下
所以主角是class Box和interface IBox
至于interface IUpdate接口,由于类Box实现了它这个接口,所以类class Box里必须要有所实现接口里的属性和方法,所以我的类class Box里有update方法
练习一下
//练习写接口,答案在下面
function createObj(className)
{
}
interface IA{
name:string;
}
class Box implements IA{
constructor(name:string){
}
}
class Ball implements IA{
constructor(name:string,age:number){
}
}
createObj(Box);
createObj(Ball);
//公布答案,仅供参考
interface IA{
names:string;
}
class Box implements IA{
names:string;
constructor(names:string){
this.names=names
}
}
class Ball implements IA{
names:string;
age?:number;
constructor(names:string,age?:number){
this.names=names;
this.age=age;
}
}
interface IBox{
new (names:string,age?:number):IA;
}
function createObj(className:IBox,names:string,age?:number)
{
return new className(names,age);//关键句,就是别忘了记住这句返回值
}
var a:IA=createObj(Box,"zhangsan");
var b:IA=createObj(Ball,"zhangsan",18);
console.log(a,b);
怎么说呢,我在努力地想讲清楚哈哈,确实对我来说还不太熟,需要多花时间练习
不过没事,我们这种方式用的也不多(划重点),我们之后会使用范式接口
//案例 类类型作为参数时,它的方法要设置为静态方法
class Box{
constructor(name:string){
}
static play():void{
console.log("aa");
}
}
class Ball{
constructor(name:string) {
}
play(){
console.log("b");
}
}
interface IBox{
new (name:string):Box|Ball
play():void;
}
function createClass(className:IBox){
var a:Ball|Box=new className("a");
}
createClass(Box)
接口的继承
interface IA{
a:number;
}
interface IB extends IA{
b:number;
}
class Box implements IB{
a:number=1;
b:number=2;
}
接口可以继承多个接口,而类只能继承一个父类
interface IA{
a:number;
}
interface IB{
b:number;
}
interface IC extends IA,IB{
c:number;
}
class Box implements IC{
a:number=1;
b:number=2;
c:number=3;
}
接口IBox继承类Box,类bBall继承接口IBox
class Box{
a:number=1;
constructor(){
}
play():void{
}
update(num:number):number{
return num+1;
}
}
interface IBox extends Box{
b:number;
}
class Ball implements IBox{
a:number=1;
b:number=2;
constructor(){
}
play():void{
}
update(num:number):number{
return num+1;
}
}
事件如果想要添加属性,就得是接口类型,这个接口继承Event并且里面写了[key:string]:any;
interface IEvent extends Event{
[key:string]:any;
}
document.addEventListener("click",clickHandler);
var evt:IEvent=new Event("click");
evt.a=1;
evt.obj={a:1,b:2}
document.dispatchEvent(evt);
function clickHandler(e:IEvent):void
{
console.log(e.a);
}
发表评论