programing

TypeScript에서는 강력한 타입의 함수를 파라미터로 사용할 수 있습니까?

subpage 2023. 3. 15. 19:35
반응형

TypeScript에서는 강력한 타입의 함수를 파라미터로 사용할 수 있습니까?

TypeScript에서는 함수의 파라미터를 Function으로 선언할 수 있습니다.제가 놓치고 있는 "타입 세이프"한 방법이 있을까요?예를 들어 다음과 같습니다.

class Foo {
    save(callback: Function) : void {
        //Do the save
        var result : number = 42; //We get a number from the save operation
        //Can I at compile-time ensure the callback accepts a single parameter of type number somehow?
        callback(result);
    }
}

var foo = new Foo();
var callback = (result: string) : void => {
    alert(result);
}
foo.save(callback);

저장 콜백은 type safe가 아닙니다. 함수의 파라미터가 문자열이지만 번호를 전달하여 오류 없이 컴파일하는 콜백 함수를 제공합니다.type-safe 함수 저장 시 result parameter를 만들 수 있습니까?

TL;DR 버전:에 상당하는 것이 있습니까?TypeScript의 NET 대리인

물론이죠. 함수의 형식은 인수 유형과 반환 형식으로 구성됩니다.여기에서는, 다음과 같이 지정합니다.callback매개 변수의 유형은 "숫자를 받아들이고 형식을 반환하는 함수"여야 합니다.any":

class Foo {
    save(callback: (n: number) => any) : void {
        callback(42);
    }
}
var foo = new Foo();

var strCallback = (result: string) : void => {
    alert(result);
}
var numCallback = (result: number) : void => {
    alert(result.toString());
}

foo.save(strCallback); // not OK
foo.save(numCallback); // OK

필요에 따라서, 타입 에일리어스를 정의하고, 다음을 캡슐화할 수 있습니다.

type NumberCallback = (n: number) => any;

class Foo {
    // Equivalent
    save(callback: NumberCallback) : void {
        callback(42);
    }
}

다음은 일반적인 몇 가지 유형 스크립트에 해당합니다.NET 대리인:

interface Action<T>
{
    (item: T): void;
}

interface Func<T,TResult>
{
    (item: T): TResult;
}
type FunctionName = (n: inputType) => any;

class ClassName {
    save(callback: FunctionName) : void {
        callback(data);
    }
}

이것은 확실히 기능 프로그래밍 패러다임과 일치합니다.

이 투고는 오래되었다는 것은 알지만, 부탁받은 것과는 조금 다른 보다 간결한 어프로치가 있습니다만, 매우 도움이 될지도 모릅니다.메서드를 호출할 때 함수를 인라인으로 선언할 수 있습니다( ).Foosave()(이 경우)를 참조해 주세요.다음과 같이 됩니다.

class Foo {
    save(callback: (n: number) => any) : void {
        callback(42)
    }

    multipleCallbacks(firstCallback: (s: string) => void, secondCallback: (b: boolean) => boolean): void {
        firstCallback("hello world")

        let result: boolean = secondCallback(true)
        console.log("Resulting boolean: " + result)
    }
}

var foo = new Foo()

// Single callback example.
// Just like with @RyanCavanaugh's approach, ensure the parameter(s) and return
// types match the declared types above in the `save()` method definition.
foo.save((newNumber: number) => {
    console.log("Some number: " + newNumber)

    // This is optional, since "any" is the declared return type.
    return newNumber
})

// Multiple callbacks example.
// Each call is on a separate line for clarity.
// Note that `firstCallback()` has a void return type, while the second is boolean.
foo.multipleCallbacks(
    (s: string) => {
         console.log("Some string: " + s)
    },
    (b: boolean) => {
        console.log("Some boolean: " + b)
        let result = b && false

        return result
    }
)

multipleCallback()어프로치는 네트워크콜 등의 성공 또는 실패에 매우 도움이 됩니다.다시 네트워크 콜의 예를 가정하면,multipleCallbacks()가 호출됩니다.성공과 실패의 양쪽 동작을 한 곳에서 정의할 수 있기 때문에 향후 코드 리더가 알기 쉽게 됩니다.

일반적으로 제 경험상 이 접근법은 더 간결하고 덜 복잡하며 전반적으로 더 명확합니다.

모두 행운을 빌어요!

TS에서는 다음과 같은 방법으로 에 함수를 입력할 수 있습니다.

함수 유형/시그니처

이 명령어는 함수/메서드의 실제 구현에 사용됩니다.구문은 다음과 같습니다.

(arg1: Arg1type, arg2: Arg2type) : ReturnType

예:

function add(x: number, y: number): number {
    return x + y;
}

class Date {
  setTime(time: number): number {
   // ...
  }

}

함수 유형 리터럴

함수 유형 리터럴은 함수 유형을 선언하는 또 다른 방법입니다.이들은 보통 고차 함수의 함수 시그니처에 적용됩니다.고차 함수는 함수를 파라미터로 받아들이거나 함수를 반환하는 함수입니다.구문은 다음과 같습니다.

(arg1: Arg1type, arg2: Arg2type) => ReturnType

예:

type FunctionType1 = (x: string, y: number) => number;

class Foo {
    save(callback: (str: string) => void) {
       // ...
    }

    doStuff(callback: FunctionType1) {
       // ...
    }

}

함수 정의와 다른 데이터 유형을 쉽게 결합할 수 없기 때문에 이러한 유형을 주변에 배치하는 것이 매우 유용하다고 생각합니다.드류 씨의 답변에 근거해서.

type Func<TArgs extends any[], TResult> = (...args: TArgs) => TResult; 
//Syntax sugar
type Action<TArgs extends any[]> = Func<TArgs, undefined>; 

이제 모든 매개 변수와 반환 유형을 강하게 입력할 수 있습니다!위의 예보다 더 많은 파라미터를 가진 예를 다음에 나타냅니다.

save(callback: Func<[string, Object, boolean], number>): number
{
    let str = "";
    let obj = {};
    let bool = true;
    let result: number = callback(str, obj, bool);
    return result;
}

이제 내보내거나 소비해야 하는 완전히 새로운 유형을 작성하지 않고도 객체나 객체를 반환하는 함수와 같은 결합 유형을 작성할 수 있습니다.

//THIS DOESN'T WORK
let myVar1: boolean | (parameters: object) => boolean;

//This works, but requires a type be defined each time
type myBoolFunc = (parameters: object) => boolean;
let myVar1: boolean | myBoolFunc;

//This works, with a generic type that can be used anywhere
let myVar2: boolean | Func<[object], boolean>;

먼저 함수 유형을 정의하면 다음과 같이 됩니다.

type Callback = (n: number) => void;

class Foo {
    save(callback: Callback) : void {        
        callback(42);
    }
}

var foo = new Foo();
var stringCallback = (result: string) : void => {
    console.log(result);
}

var numberCallback = (result: number) : void => {
    console.log(result);
}

foo.save(stringCallback); //--will be showing error
foo.save(numberCallback);

플레인 속성 구문을 사용하여 함수 유형을 지정하지 않으면 다음과 같습니다.

class Foo {
    save(callback: (n: number) => void) : void {        
        callback(42);
    }
}

var foo = new Foo();
var stringCallback = (result: string) : void => {
    console.log(result);
}

var numberCallback = (result: number) : void => {
    console.log(result);
}

foo.save(stringCallback); //--will be showing error
foo.save(numberCallback);

c# generic disples 등의 인터페이스 기능을 사용하는 경우는, 다음과 같습니다.

interface CallBackFunc<T, U>
{
    (input:T): U;
};

class Foo {
    save(callback: CallBackFunc<number,void>) : void {        
        callback(42);
    }
}

var foo = new Foo();
var stringCallback = (result: string) : void => {
    console.log(result);
}

var numberCallback = (result: number) : void => {
    console.log(result);
}

let strCBObj:CallBackFunc<string,void> = stringCallback;
let numberCBObj:CallBackFunc<number,void> = numberCallback;

foo.save(strCBObj); //--will be showing error
foo.save(numberCBObj);

다른 사람이 말한 것 외에 일반적인 문제는 과부하된 동일한 함수의 유형을 선언하는 것입니다.일반적으로 여러 종류의 청취자를 받아들이는 EventEmiter on() 메서드가 있습니다.redux 액션으로 작업할 때도 마찬가지로 액션유형을 리터럴로 사용하여 오버로드를 마크합니다.EventEmitters의 경우 이벤트명 리터럴타입을 사용합니다.

interface MyEmitter extends EventEmitter {
  on(name:'click', l: ClickListener):void
  on(name:'move', l: MoveListener):void
  on(name:'die', l: DieListener):void
  //and a generic one
  on(name:string, l:(...a:any[])=>any):void
}

type ClickListener = (e:ClickEvent)=>void
type MoveListener = (e:MoveEvent)=>void
... etc

// will type check the correct listener when writing something like:
myEmitter.on('click', e=>...<--- autocompletion
function callbackTesting(callbacks: {onYes: (data: any) => void,onNo: (data: any) => void,onError: (err: any) => void,}, type: String){
        switch(type){
            case "one": 
            callbacks.onYes("Print yes");
            break;
            case "two": 
            callbacks.onNo("Print no");
            break;
            default:
            callbacks.onError("Print error");
            break;
        }
    }

    const onYes1 = (data: any) : void => {
        console.log(data);
    }
    const onNo1 = (data: any) : void => {
        console.log(data);
    }
    const onError1 = (data: any) : void => {
        console.log(data);
    }



    callbackTesting({onYes: function (data: any)  {onYes1(data);},onNo: function (data: any)  {onNo1(data);},onError: function (data: any)  {onError1(data);}}, "one");

    callbackTesting({onYes: function (data: any)  {onYes1(data);},onNo: function (data: any)  {onNo1(data);},onError: function (data: any)  {onError1(data);}}, "two");

    callbackTesting({onYes: function (data: any)  {onYes1(data);},onNo: function (data: any)  {onNo1(data);},onError: function (data: any)  {onError1(data);}}, "cfhvgjbhkjlkm");

언급URL : https://stackoverflow.com/questions/14638990/are-strongly-typed-functions-as-parameters-possible-in-typescript

반응형