Bản mô tả: Cách xác định loại cho một hàm gọi lại (như bất kỳ loại hàm nào, không phổ biến bất kỳ) được sử dụng trong một tham số phương thức


313

Hiện tại tôi có định nghĩa kiểu như:

interface Param {
    title: string;
    callback: any;
}

Tôi cần một cái gì đó như:

interface Param {
    title: string;
    callback: function;
}

nhưng cái thứ 2 không được chấp nhận.

Câu trả lời:


285

Loại toàn cầu Functionphục vụ mục đích này.

Ngoài ra, nếu bạn có ý định gọi lại cuộc gọi này với 0 đối số và sẽ bỏ qua giá trị trả về của nó, loại () => voidkhớp với tất cả các hàm không có đối số.


27
điều này bị thiếu trong các loại cơ bản
Yogesh

13
Đây không phải là loại cơ bản vì bạn nên xác định đối số và trả về giá trị. một cái gì đó như gọi lại: (số: số) => void; hữu ích hơn nhiều cho việc kiểm tra kiểu so với gọi lại: function; sẽ là
kpup

@kpup Để rõ ràng, bạn có nói không sử dụng vốn F Functionnhư trong dòng đầu tiên của câu trả lời này không, và nói đoạn thứ hai (sử dụng loại () => voidhoặc bất cứ điều gì phù hợp với trường hợp sử dụng) được ưu tiên?
ruffin

2
FWIW, tài liệu về các loại chức năng có sẵn ở đây
bắt đầu từ

191

Bản đánh máy từ v1.4 có typetừ khóa khai báo bí danh loại (tương tự như typedeftrong C / C ++). Bạn có thể khai báo kiểu gọi lại của mình, do đó:

type CallbackFunction = () => void;

trong đó khai báo một hàm không có đối số và không trả về gì. Hàm lấy không hoặc nhiều đối số thuộc bất kỳ loại nào và trả về không có gì sẽ là:

type CallbackFunctionVariadic = (...args: any[]) => void;

Sau đó, bạn có thể nói, ví dụ,

let callback: CallbackFunctionVariadic = function(...args: any[]) {
  // do some stuff
};

Nếu bạn muốn một hàm lấy số lượng đối số tùy ý và trả về bất cứ thứ gì (bao gồm khoảng trống):

type CallbackFunctionVariadicAnyReturn = (...args: any[]) => any;

Bạn có thể chỉ định một số đối số bắt buộc và sau đó là một tập hợp các đối số bổ sung (giả sử một chuỗi, một số và sau đó là một tập hợp các đối số phụ), do đó:

type CallbackFunctionSomeVariadic =
  (arg1: string, arg2: number, ...args: any[]) => void;

Điều này có thể hữu ích cho những thứ như trình xử lý EventEuctor.

Các chức năng có thể được gõ mạnh như bạn muốn trong thời trang này, mặc dù bạn có thể bị mang đi và gặp phải các vấn đề liên hợp nếu bạn cố gắng khắc phục mọi thứ bằng một bí danh loại.


1
Giữa Function(...args: any[]) => anynhững gì được ưa thích?
ahong

@ahong: Cá nhân tôi thích cái sau vì nó cung cấp chữ ký ... bình thường. ...args: any[]không hữu ích lắm
Ed S.

type CallbackFunctionSomeVariadic = (arg1: string, arg2: number, ...args: any[]) => void;những gì tôi đang tìm kiếm, ty.
aqteifan

61

Theo câu trả lời của Ryan, tôi nghĩ rằng giao diện bạn đang tìm kiếm được xác định như sau:

interface Param {
    title: string;
    callback: () => void;
}

34

Đây là một ví dụ về chức năng chấp nhận gọi lại

const sqk = (x: number, callback: ((_: number) => number)): number => {
  // callback will receive a number and expected to return a number
  return callback (x * x);
}

// here our callback will receive a number
sqk(5, function(x) {
  console.log(x); // 25
  return x;       // we must return a number here
});

Nếu bạn không quan tâm đến giá trị trả về của các cuộc gọi lại (hầu hết mọi người không biết cách sử dụng chúng theo bất kỳ cách hiệu quả nào), bạn có thể sử dụng void

const sqk = (x: number, callback: ((_: number) => void)): void => {
  // callback will receive a number, we don't care what it returns
  callback (x * x);
}

// here our callback will receive a number
sqk(5, function(x) {
  console.log(x); // 25
  // void
});

Lưu ý, chữ ký tôi đã sử dụng cho callbacktham số ...

const sqk = (x: number, callback: ((_: number) => number)): number

Tôi muốn nói rằng đây là một thiếu sót TypeScript vì chúng tôi dự kiến ​​sẽ cung cấp một tên cho các tham số gọi lại. Trong trường hợp này tôi đã sử dụng _vì nó không thể sử dụng được bên trongsqk hàm.

Tuy nhiên, nếu bạn làm điều này

// danger!! don't do this
const sqk = (x: number, callback: ((number) => number)): number

Đó là TypeScript hợp lệ , nhưng nó sẽ được hiểu là ...

// watch out! typescript will think it means ...
const sqk = (x: number, callback: ((number: any) => number)): number

Tức là, TypeScript sẽ nghĩ tên tham số là numbervà kiểu ngụ ý là any. Đây rõ ràng không phải là những gì chúng tôi dự định, nhưng than ôi, đó là cách TypeScript hoạt động.

Vì vậy, đừng quên cung cấp tên tham số khi nhập tham số chức năng của bạn ... thật ngu ngốc.


32

Bạn có thể định nghĩa một loại chức năng trong giao diện theo nhiều cách khác nhau,

  1. Cách chung:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. Nếu bạn muốn sử dụng cú pháp thuộc tính thì,
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. Nếu bạn khai báo kiểu hàm trước, thì
type MyFnType = (arg1: number, arg2: number) => number;

export interface IParam {
  title: string;
  callback: MyFnType;
}

Sử dụng là rất thẳng về phía trước,

function callingFn(paramInfo: IParam):number {
    let needToCall = true;
    let result = 0;
   if(needToCall){
     result = paramInfo.callback(1,2);
    }

    return result;
}
  1. Bạn cũng có thể khai báo một kiểu hàm, nghĩa là một hàm có thể chấp nhận hàm khác làm tham số. chức năng tham số hóa có thể được gọi là gọi lại cũng.
export interface IParam{
  title: string;
  callback(lateCallFn?:
             (arg1:number,arg2:number)=>number):number;

}

10

Có bốn loại hàm trừu tượng, bạn có thể sử dụng chúng một cách riêng biệt khi bạn biết hàm của mình sẽ có (các) đối số hay không, sẽ trả về dữ liệu hay không.

export declare type fEmptyVoid = () => void;
export declare type fEmptyReturn = () => any;
export declare type fArgVoid = (...args: any[]) => void;
export declare type fArgReturn = (...args: any[]) => any;

như thế này:

public isValid: fEmptyReturn = (): boolean => true;
public setStatus: fArgVoid = (status: boolean): void => this.status = status;

Để chỉ sử dụng một loại như bất kỳ loại chức năng nào, chúng tôi có thể kết hợp tất cả các loại trừu tượng lại với nhau, như thế này:

export declare type fFunction = fEmptyVoid | fEmptyReturn | fArgVoid | fArgReturn;

sau đó sử dụng nó như sau:

public isValid: fFunction = (): boolean => true;
public setStatus: fFunction = (status: boolean): void => this.status = status;

Trong ví dụ trên mọi thứ đều đúng. Nhưng ví dụ sử dụng dưới đây không đúng theo quan điểm của hầu hết các biên tập viên mã.

// you can call this function with any type of function as argument
public callArgument(callback: fFunction) {

    // but you will get editor error if call callback argument like this
    callback();
}

Gọi chính xác cho các biên tập viên là như thế này:

public callArgument(callback: fFunction) {

    // pay attention in this part, for fix editor(s) error
    (callback as fFunction)();
}

2

Bản mô tả: Làm thế nào để xác định loại cho một hàm gọi lại được sử dụng trong một tham số phương thức ?

Bạn có thể khai báo callback như 1) sở hữu chức năng hoặc 2) phương pháp :

interface ParamFnProp {
    callback: (a: Animal) => void; // function property
}

interface ParamMethod {
    callback(a: Animal): void; // method
}

Có một sự khác biệt quan trọng về kể từ TS 2.6 :

Bạn nhận được các loại mạnh hơn ("âm thanh") trong --stricthoặc --strictFunctionTypeschế độ, khi một thuộc tính chức năng được khai báo. Hãy lấy một ví dụ:

const animalCallback = (a: Animal): void => { } // Animal is the base type for Dog
const dogCallback = (d: Dog): void => { } 
// function property variant
const param11: ParamFnProp = { callback: dogCallback } // error: not assignable
const param12: ParamFnProp = { callback: animalCallback } // works

// method variant
const param2: ParamMethod = { callback: dogCallback } // now it works again ...

Về mặt kỹ thuật nói, phương pháp này bivariant và tính chức năng contravariant trong lập luận của họ dưới strictFunctionTypes. Các phương thức vẫn được kiểm tra một cách dễ dàng hơn (ngay cả khi không có âm thanh) để thực tế hơn một chút khi kết hợp với các loại tích hợp nhưArray .

Tóm lược

  • Có một sự khác biệt về kiểu giữa thuộc tính hàm và khai báo phương thức
  • Chọn một thuộc tính chức năng cho các loại mạnh hơn, nếu có thể

Mã mẫu sân chơi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.