blog

タイプスクリプトのフラッディング + デコレーター (IV)

ジェネリックス: ソフトウェア・エンジニアリングでは、一貫性のある明確に定義された API を作成するだけでなく、再利用性を考慮することも重要です。 コンポーネントが現在のデータ型だけでなく将来のデー...

Sep 25, 2020 · 13 min. read
シェア

typeScriptのジェネリック型は

  1. ジェネリックの定義
  2. ジェネリック関数
  3. 汎用クラス
  4. 汎用インターフェース

ジェネリック型の定義

ジェネリックス: ソフトウェア・エンジニアリングは、一貫性のある明確に定義されたAPIを作成するだけでなく、再利用性も重要です。 コンポーネントが現在のデータ型だけでなく将来のデータ型もサポートできることは、大規模なシステムを作成する際に大きな柔軟性をもたらします。

C#やJavaなどの言語では、ジェネリックスを使って再利用可能なコンポーネントを作成することができます。 これにより、ユーザーは独自のデータ型でコンポーネントを使用できます。

一般的に、ジェネリックスはクラスのインターフェイスやメソッドの再利用性、不特定のデータ型のサポートに対応しています。

ジェネリック型では、型パラメータは開き括弧と閉じ括弧の間に記述され、これは強く型付けされた集合になります。ジェネリック型は型を表す特別な型の変数を使用します。ジェネリック・コレクションは類似した型のオブジェクトだけを含みます。

function identity<T>(arg: T): T { 
 return arg; 
} 
let output1 = identity<string>("myString"); 
let output2 = identity<number>( 100 ); 
console.log(output1); 
console.log(output2); 

ジェネリック関数

文字列型のデータのみを返すことができます。

function getData(value:string):string{
 return value;
 }

文字列型と数値型の両方を返す必要があります。

function getData1(value:string):string{
 return value;
}
function getData2(value:number):number{
 return value;
}

文字列と数値の両方を返すanyは、この問題を解決します。

function getData(value:any):any{
 return value+'hello';
}
getData(123);
getData('str');

そのため、入力されるパラメータの型と返されるパラメータの型が一致しないことがあります。

 //any値の型は渡されるが、戻り値の型が利用できないという問題がある。
 function getData<T>(value:T):any{
 return '';
 }
 getData<number>(123); //パラメータは必ず番号でなければならない。
 getData<string>('これは一般的な');

何かを渡せば、何かを返します。例えば、数値を渡せば数値を返さなければなりませんし、文字列を渡せば文字列を返さなければなりません。

Generic: 関数/インターフェース/クラスの定義時に特定の型を指定せず、使用時に指定する機能。

Tは汎用型を表し、正確な型はこのメソッドを呼び出すときに決定されます。

 //T 汎用変数 任意の型を示す
function getData<T>(value:T):T{
 return value;
 }
getData<number>(123);
getData<string>('');
getData<number>('2112'); /*間違った書き方*/ 

// これは、関数/インターフェース/クラスを定義する際に、あらかじめ特定の型を指定するのではなく、使用時に型を指定する機能である;
 //T 汎用変数 任意の型を示す
function fun3<T>(name:T):T{ 
 console.log('hello ' + name);
 return name; 
};
fun3<string>('abc'); 
//ジェネリック関数を定義した後、メソッド
// 複数の型を定義する
fun3<string | number>('abc'); 

汎用クラス

要件:たとえば、数値と文字列 a ~ z の両方を返す必要がある最小ヒープ・アルゴリズムがあります。 これは、クラス


//以下は数値型のみをサポートする
class MinClass{
 public list:number[]=[];
 add(num:number){
 this.list.push(num)
 }
 min():number{
 // var minNum = Math.min(...this.list)
 //数値と文字列を比較するので、以下のメソッドを使用する。
 var minNum=this.list[0];
 for(var i=0;i<this.list.length;i++){
 if(minNum>this.list[i]){
 minNum=this.list[i];
 }
 }
 return minNum;
 }
}
var m=new MinClass();
m.add(30);
m.add(22);
m.add(6);
alert(m.min());

数値と文字列の大きさを同時に比較するには?

クラスジェネリックの活用

class MinClas<T> {
 public list: T[] = [];
 add(value: T): void {
 this.list.push(value);
 }
 min(): T {
 var minNum = this.list[0];
 for (var i = 0; i < this.list.length; i++) {
 if (minNum > this.list[i]) {
 minNum = this.list[i];
 }
 }
 return minNum;
 }
}
//クラスをインスタンス化し、クラスのT表現の型をnumberと指定する。
var m1=new MinClas<number>(); 
m1.add(11);
m1.add(3);
m1.add(2);
alert(m1.min())
// クラスをインスタンス化し、クラスの T 表現の型を string と指定する。
var m2 = new MinClas<string>();
m2.add("b");
m2.add("k");
m2.add("v");
alert(m2.min());

汎用関数の定義


//関数の宣言
function fun5<T>(name:T):T{ 
 return name
}
//関数式
let fun6 = function<A>(name:A):A{
 return name;
}
//ES6
 let fun7 =<U>(name:U):U => name;

汎用インターフェース

関数型インタフェース


interface ConfigFn{
 (value1:string,value2:string):string;
}
var setData:ConfigFn=function(value1:string,value2:string):string{
 return value1+value2;
}
setData('name',' ');

文字列と数値の両方のインターフェイスをサポートしたい場合、上記の関数インターフェイスは機能しません。

汎用インターフェース

インターフェイスでのジェネリックの定義

interface ConfigFn{
 <T>(value:T):T;
}
var getData:ConfigFn=function<T>(value:T):T{
 return value;
}
getData<string>(' ');
// getData<string>(1243); // 

汎用インターフェース

interface ConfigFn<T> {
 (value: T): T;
}
function getData<T>(value: T): T {
 return value;
}
var myGetData: ConfigFn<string> = getData;
myGetData("20"); /* */
// myGetData(20) // 

 // 
interface Search{ 
 <T>(a:T,b:T):boolean;
}
// Interface Searchは、任意の型の2つのパラメータを持ち、パラメータの型が一致し、真偽値を返すメソッドを表す。
// 以下はインターフェイスを使用している:
let f4:Search = function<T>(str1:T,str2:T):boolean{ //void戻り値はない。
 return str1==str2; //true/false
}
f4<number>()

授業におけるパノタイプの使用


class A2<T>{
 n:T; //プロパティの型を示す
 constructor(num:T){ //値の型
 this.n = num;
 }
 action(x:T):T{
 return x
 }
};
var a2 = new A2<string>('abc'); //インスタンス化
a2.action('3')

TypeScript の汎用クラス クラスをパラメータ型として受け取る汎用クラス。

クラスをパラメータとして使用し、渡されるデータの型を制限します。


class User{
 username:string | undefined;
 pasword:string | undefined;
 constructor(username:string,pasword:string) {
 this.username = username;
 this.pasword = pasword;
 }
 }
 
 class MysqlDb{
 allUser:any[] = [];
 add(user:User):boolean{
 console.log(user);
 this.allUser.push(user)
 return true;
 }
 getUsers(){
 console.log(this.allUser)
 }
 }
 var u1=new User(' ','');
 var u2=new User(' ','');
 var Db=new MysqlDb();
 Db.add(u1);
 Db.add(u2);
 Db.getUsers();
 

配列ジェネリックス

//配列のジェネリックであるArrayは、配列を表すのにも使えます。

let arr: Array<any> = [1, '1', true, 3, 5]; //number[]

返り値の型の定義 T

関数名の後に , を追加します。ここで、T は任意の入力型を指すために使用され、入力値:T と出力 Array で後で使用することができます。

 function createArray2<T>(length: number, value: T): Array<T> {
 let result: T[] = [];
 for (let i = 0; i < length; i++) {
 result[i] = value;
 }
 return result;
}
createArray2<string>(3, 'x');

デコレータ

装飾家の例はあちこちにあります。

バブラーの上部に蛇口は、空気のインストールが水の中に多くの泡と混合され、水流に混合された後、装飾です。しかし、蛇口自体にバブラーのインストールかどうかは、バブラーの除去であっても、何の影響も持っていない、また、いつものように動作します、タップの役割は、水のように、バルブの制御である泡と混合されていない蛇口は気にする必要はありません。

デコレーターの書き方:ノーマルデコレーター、デコレーターファクトリー

デコレーターは、ここ数年におけるjsの最大の成果のひとつであり、すでにEs7の標準機能のひとつとなっています。

デコレーターを使う理由

入ってくるパラメータの型判定、戻り値のソートやフィルタリング、 スロットリングやアンチジッタリング、その他の機能的なコードの関数への追加、 複数のクラスに基づく継承など、関数のロジック自体とは関係のない、 あらゆる種類の反復的なコードが必要になることもあるでしょう。つまり、デコレータを使用することで、押し付けがましくない振る舞いの修正と理解することができます。

デコレータを使用する際の重要なルール

元の機能を上書きするのではなく、デコレータで機能を拡張する場合

デコレータの役割

ビジネスコードの開発に集中させ、機能的なサポートコードをカプセル化します。ポイントは、ビジネスへのフォーカスを維持し、フォーカスの分離を達成することです。

デコレータの定義方法

デコレータ自体は実際には関数で、引数を無視すれば理論的にはどんな関数でもデコレータとして使えます。

helloword.ts


function helloWord(target: any) {
 // target.username = 'dddd';
 console.log('hello Word!');
}
@helloWord
class HelloWordClass {
 // static username:string;
}
var p1 = new HelloWordClass();

デコレータの実行タイミング

モディファイアによるクラスの振る舞いの変更は、実行時ではなく、コードがコンパイルされるときに起こります。つまり、モディファイアはコンパイル時にコードを実行することができます。つまり、モディファイアは本質的にコンパイル時に実行される関数なのです。

デコレータの種類

一般的なデコレータは、クラス・デコレータ、プロパティ・デコレータ、メソッド・デコレータ、パラメータ・デコレータです。

クラス・デコレータ

クラス・デコレータはクラス宣言で宣言します。 クラス・デコレータはクラス・コンストラクタに適用され、 クラス定義の監視や変更、置換に使用できます。パラメータをひとつ渡します。

通常のデコレータ


function logClass(target:any){
 console.log(target);
 // target は現在のクラス
 target.prototype.apiUrl='動的に拡張されるプロパティ';
 target.prototype.run=function(){
 console.log('実行メソッド');
 }
}
@logClass
class HttpClient{
 constructor(){
 }
 getData(){
 }
}
var http:any=new HttpClient();
console.log(http.apiUrl);
http.run();

デコレータにパラメータを渡す必要がある場合は、 JavaScript の関数 currying 機能を使用します。

クラス・デコレーター:デコレーター・ファクトリー

 function logClass(params:string){
 // target デコレーターは、カレントクラスである
 return function(target:any){ // これが本当のデコレーターだ。
 console.log(target);
 console.log(params);
 target.prototype.apiUrl=params;
 }
 }
 // @logClass('http://./pi') は即時関数で、実際には logClass 内のクロージャ関数を返す。
 @logClass('http://./pi')
 class HttpClient{
 constructor(){
 }
 getData(){
 }
 }
 var http:any=new HttpClient();
 console.log(http.apiUrl);

属性デコレータ

属性デコレータ式は、実行時に関数として呼び出され、属性に値を割り当てます。 1. 静的メンバの場合はクラスのコンストラクタ、インスタンス・メンバの場合はクラスのプロトタイプ・オブジェクト。2. メンバの名前。

 //クラス・デコレータは、パラメータ
 function logClass(params:string){
 return function(target:any){
 console.log(target);
 console.log(params); 
 }
 }
 //属性デコレーター
 function logProperty(params:any){
 
 console.log(params); //ruanmou.com
 return function(target:any,attr:any){
 console.log(target); //HttpClientプロトタイプメソッドの
 console.log(attr); // デコレーターを使用するプロパティ,url
 target[attr]=params;
 }
 }
 @logClass('xxxx')
 class HttpClient {
 @logProperty('ruanmou.com')
 public url:any |undefined;
 // @logProperty('laney')
 public name:string | undefined;
 constructor(str:string){
 // this.name = str;
 }
 getData(){
 console.log(this.url);
 }
 say(){
 console.log(this.name);
 }
 }
 var http=new HttpClient('hello');
 http.getData();

メソッド・デコレータ

これはメソッドのプロパティ記述子に適用され、メソッド定義の監視、変更、置換に使用できます。

メソッドの装飾は、実行時に以下の 3 つのパラメータを渡します。1. 静的メンバの場合はクラス・コンストラクタ、インスタンス・メンバの場合はクラス・プロトタイプ・オブジェクト。2. メンバの名前。3. メンバのプロパティ記述子。

メソッド・デコレーター 1

function get(params:any){
 return function(target:any,methodName:any,desc:any){
 
 console.log(target);
 console.log(methodName);
 console.log(desc);
 target.apiUrl='xxxx';
 target.run=function(){
 console.log('run');
 }
 }
 }
 class HttpClient{ 
 public url:any |undefined;
 constructor(){
 }
 @get('http://..om')
 getData(){
 console.log(this.url);
 }
 }
 var http:any=new HttpClient();
 console.log(http.apiUrl);
 http.run();

メソッド・デコレータ II

function get(params:any){
 return function(target:any,methodName:any,desc:any){
 console.log(target);
 console.log(methodName);
 console.log(desc.value); 
 
 //デコレーターのメソッドを変更する デコレーターのメソッド内で渡されるパラメーターをすべて文字列型に変更する。
 //1メソッドを実行し、現在のメソッドを保存する
 var oMethod=desc.value;
 desc.value=function(...args:any[]){ 
 args=args.map((value)=>{
 return String(value);
 })
 oMethod.apply(this,args);
 }
 }
}
class HttpClient{ 
 public url:any |undefined;
 constructor(){
 }
 @get('http://..om')
 getData(...args:any[]){
 console.log(args);
 console.log('getDataメソッド内部');
 }
}
var http=new HttpClient();
http.getData(123,'xxx');

パラメータ・デコレータ

パラメータ・デコレーター式は実行時に関数として呼び出され、 以下の3つのパラメータを渡すことで、クラスのプロトタイプに要素データを追加することができます:

1、静的メンバの場合はクラスのコンストラクタ、インスタンスメンバの場合はクラスのプロトタイプオブジェクト。2, メソッドの名前。3, 関数のパラメータリストにおけるパラメータのインデックス。

function logParams(params: any) {
 // 1静的メンバにはクラス・コンストラクタ、インスタンス・メンバにはクラス・プロトタイプ・オブジェクトを使用する。
 // 2メソッド名
 // 3関数のパラメータ・リストで、パラメータのインデックスを指定する。
 return function (target: any, methodName: any, paramsIndex: any) {
 // console.log(params);
 // console.log(target);
 // console.log(methodName);
 // console.log(paramsIndex);
 target.apiUrl = params;
 };
 }
 class HttpClient {
 public url: any | undefined;
 constructor() {}
 getData(@logParams("3yteam.com") uuid: any) {
 console.log(uuid);
 }
 }
 var http: any = new HttpClient();
 http.getData();
 console.log(http.apiUrl);

アクセサ・デコレータ

アクセサーデコレーターは、アクセサーのプロパティ記述子に適用され、 アクセサーの定義を観察したり、変更したり、置き換えたりするのに使えます。 アクセサデコレータは、宣言ファイルやその他の環境コンテキストでは使えません。

注意: TypeScript では、ひとつのメンバに対して get アクセサと set アクセサをデコレートすることはできません。その代わりに、そのメンバに対するすべてのデコレータを、ドキュメント順で最初に指定したアクセサに適用しなければなりません。これは、デコレータが各宣言に対して個別に適用されるのではなく、プロパティ記述子に対して適用されるためです。

アクセサデコレーター式は、実行時に関数として呼び出され、以下の3つのパラメータを渡します:

  1. 静的メンバの場合はクラスのコンストラクタ、インスタンス・メンバの場合はクラスのプロトタイプ・オブジェクトです。
  2. メンバの名前
  3. メンバのプロパティ記述子。

以下は、Point クラスのメンバに適用されるアクセサ・デコレーターの例です:

function configurable(value: boolean) {
 return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 descriptor.configurable = value;
 };
}
 class Point {
 private _x: number;
 private _y: number;
 constructor(x: number, y: number) {
 this._x = x;
 this._y = y;
 }
 @configurable(false)
 get x() { return this._x; }
 @configurable(false)
 get y() { return this._y; }
}

デコレータの実行順序

プロパティ、メソッド、メソッド・パラメータ、クラス

同じデコレータが複数ある場合は、 後から実行されたものから順に実行されます。

function logClass1(params:string){
 return function(target:any){
 console.log('クラス・デコレーター 1')
 }
 }
 
 function logClass2(params:string){
 return function(target:any){
 console.log('クラス・デコレーター 2')
 }
 }
 
 function logAttribute1(params?:string){
 return function(target:any,attrName:any){
 console.log('属性デコレーター 1')
 }
 }
 
 function logAttribute2(params?:string){
 return function(target:any,attrName:any){
 console.log('属性デコレーター 2')
 }
 }
 
 function logMethod1(params?:string){
 return function(target:any,attrName:any,desc:any){
 console.log('メソッド・デコレーター 1')
 }
 }
 function logMethod2(params?:string){
 return function(target:any,attrName:any,desc:any){
 console.log('メソッド・デコレーター 2')
 }
 }
 
 function logParams1(params?:string){
 return function(target:any,attrName:any,desc:any){
 console.log('メソッド・パラメータ・デコレーター 1')
 }
 }
 
 function logParams2(params?:string){
 return function(target:any,attrName:any,desc:any){
 console.log('メソッド・パラメータ・デコレーター 2')
 }
 }
 
 @logClass1('http://../pi')
 @logClass2('xxxx')
 class HttpClient{
 @logAttribute1()
 @logAttribute2()
 public apiUrl:string | undefined;
 constructor(){
 }
 
 @logMethod1()
 @logMethod2()
 getData(){
 return true;
 }
 
 setData(@logParams1() attr1:any,@logParams2() attr2:any,){
 
 }
 }
 
 var http:any=new HttpClient();
Read next

PHPの開発者は、マルチプロセスの消費キューを知っておくべきである

はじめに 最近、キューmcqを使用して、小さな機能を開発し、キューデータを消費するプロセスを開始し、後でプロセスがオーバー処理できないことが判明し、プロセスを追加し、一定期間後に、オーバー処理することはできません...この方法では、毎回、プロセスがハングアップした場合、時間内にされませんcrontabを変更する必要があります!

Sep 25, 2020 · 10 min read