在Typescript中联合类型的两个函数

时间:2017-04-27 16:04:06

标签: typescript types

我有一种情况,我有一个类型是两个函数的联合,它们的文字值作为其参数之一的类型。归结为一个最小的例子,基本上是这样的:

type FetchMini = (id: number, representation: 'mini') => MiniUser;
type FetchFull = (id: number, representation: 'full') => FullUser;

function f(fetchUser: FetchMini | FetchFull) {
  fetchUser(2, 'mini');
  fetchUser(2, 'full');
}

这两个调用都使编译器失败:

  

无法调用类型缺少调用签名的表达式。输入' FetchMini | FetchFull'没有兼容的电话签名。

我理解为什么会发生这种情况,(......我想),但我该怎么办呢?

这是一个类似的问题,但它没有答案:Union of functions is not callable even with parameters that meet each function's constraints

3 个答案:

答案 0 :(得分:9)

您的fetchUser()本质上是一个重载函数,它接受 minifull,因此应该交集 -typed,而不是结合。

type MiniUser = { name: string }
type FullUser = { firstName: string, lastName: string, age: number }

type FetchMini = (id: number, representation: 'mini') => MiniUser;
type FetchFull = (id: number, representation: 'full') => FullUser;
type FetchBoth = FetchMini&FetchFull

function f(fetchUser: FetchBoth) {
    fetchUser(2, 'mini');
    fetchUser(2, 'full');
}

function fetchBoth(id: number, representation: 'mini'): MiniUser
function fetchBoth(id: number, representation: 'full'): FullUser
function fetchBoth(id: number, representation: 'mini' | 'full') {
    if (representation==='mini')
        return { name: 'Mini' }
    if (representation==='full')
        return { firstName: 'Full', lastName: 'User', age: 20 }
}
f(fetchBoth)

PlayGround

根据经验,当您声明一个接受 类型A B的args的函数时,该函数应为& -typed。

答案 1 :(得分:0)

好吧,看起来最初的想法有点不正确。您应该决定您希望实现的行为。

从我所看到的, f 接受一个负责获取用户的功能。根据提供的功能,将返回 MiniUser FullUser 。如果我的建议是正确的,那么请考虑以下示例:

class MiniUser {
    name: string;

    constructor(name: string) {
        this.name = name;
    }
}

class FullUser extends MiniUser {
    age: number;

    constructor(name: string, age: number) {
        super(name);
        this.age = age;
    }
}

function fetchMiniFn(id: number) {
    return new MiniUser("John");
}

function fetchFullFn(id: number) {
    return new FullUser("John", 22);
}

function f(fetchUser: (id: number) => MiniUser | FullUser) {
    let a = fetchUser(2);
    if (a instanceof FullUser) {
        console.log("Full User: " + a.name + ", " + a.age);
    }
    else {
        console.log("Mini User: " + a.name);
    }
}

// Call the function to fetch MiniUser
f(fetchMiniFn);

// Call the function to fetch FullUser
f(fetchFullFn);


如果我的初始建议不正确,您仍然希望函数 f 决定必须提取哪种用户,而不是将上面的代码转换为:

function fetch(id: number, representation: 'mini' | 'full') {
    if (representation == 'mini') {
        return new MiniUser("John");
    }
    else {
        return new FullUser("John", 22);
    }
}

type FetchUser = (id: number, representation: 'mini' | 'full') => MiniUser | FullUser;

function f(fetchUser: FetchUser) {
    // Call the function with MiniUser fetching
    let mini = <MiniUser>fetchUser(2, 'mini');
    console.log("Mini User: " + mini.name);

    // Call the function with FullUser fetching
    let full = <FullUser>fetchUser(2, 'full');
    console.log("Full User: " + full.name + ", " + full.age);
}

// Call function:
f(fetch);

答案 2 :(得分:-1)

您可以使用通用和扩展轻松解决它(在打字稿2.7.2中为我工作)


let capacity = 200;
let reservedRooms = 0;
let users = [];

let rsBox = document.getElementById('reservebox');

class Reserver {
    constructor(name , lastName , nCode , rooms){
        this.name = name ;
        this.lastName = lastName ;
        this.nCode = nCode ;
        this.rooms = rooms ;
    }

    saveUser(){
        if(this.rooms > capacity){
            console.log('more than capacity');
        }else{
            users.push({
                name : this.name ,
                lastName : this.lastName ,
                id : this.nCode ,
                rooms : this.rooms
            });
            capacity -= this.rooms ;
            reservedRooms += this.rooms ;
        }
    }

    saveData(){
        localStorage.setItem('list',JSON.stringify(users));
    }



}


rsBox.addEventListener('submit',function(e){

    let rsName = document.getElementById('name').value;
    let rsLastName = document.getElementById('lastname').value;
    let rsNationalCode = Number(document.getElementById('nationalcode').value);
    let rooms = Number(document.getElementById('rooms').value);

    //Save the user data
    let sign = new Reserver(rsName , rsLastName , rsNationalCode , rooms);
    sign.saveUser();
    sign.saveData();





    e.preventDefault();
});