【问题标题】:Can I enforce the last argument of a function in typescript?我可以在打字稿中强制执行函数的最后一个参数吗?
【发布时间】:2017-06-01 12:21:15
【问题描述】:

假设我有一个function type interface,我想用它来强制执行特定函数的特定签名。

有没有办法强制函数的最后一个参数必须是特定类型?

有没有办法做这样的事情:

interface SomeType { /*...*/ }

/**
 * this is the function type I want to enforce
 * I want the last argument of any `Modifcation` to be `SomeType`
 */
interface Modification {
    (...args: [...firstArgs: any[], lastArgument: SomeType]): void
}

// enforcing `Modification`
const someModification: Modification = (firstParam: string, second: number, third: SomeType) => {
    /*...*/
}

我知道打字稿使用spread syntax 和tuple types,但上面的伪代码不起作用。

有没有办法做到这一点?


编辑:

免责声明:我认为没有办法做我想做的事,因此这个问题可能不是完全有建设性的。

上下文:

我有一组类,我想对这些类的特定方法强制执行某种约定。我可以通过声明另一个interface and saying that my class implements that interface 来强制某个方法必须符合function type。

例如

interface Convention {(arg0: string, arg1: number): Something}

interface MyClassMethodRequirements {
    myMethod: Convention,
    myOtherMethod: Convention
}

class MyClass implements MyClassMethodRequirements {
    myMethod(a: string, b: number) { return new Something(); }
    myOtherMethod(label: string, aNumber: number) { return new Something(); }
    otherMethod() { return 'just another non-conforming method' }
}

我想要达到的目标:

上面的Convention 只是一个例子。我要强制执行的是断言为Convention 的方法必须具有/考虑两个参数。

例如(伪代码)

interface NewConvention {(firstArg: any, lastArg?: RequiredType): Something}

interface MyClassMethodRequirements {
    myMethod: NewConvention,
    myOtherMethod: NewConvention
}

class MyClass implements MyClassMethodRequirements {
    myMethod(a: string, b?: RequiredType) { return new Something(); }
    // i want an error here because `myOtherMethod` doesn't list `lastArg: RequiredType` in it's parameters
    myOtherMethod(label: string) { return new Something(); }
    otherMethod() { return 'just another non-conforming method' }
}

对于更多上下文,NewConvention 的 lastArg 应该是可选的覆盖。

再说一次,我不认为我想要达到的目标是可能的,所以这可能没有建设性。

感谢您的帮助:)

【问题讨论】:

  • 我很确定目前这是不可能的(检查这个问题:github.com/Microsoft/TypeScript/issues/1336),但你为什么不把最后一个参数移到第一个参数并避免这个问题?
  • @NitzanTomer 最后一个参数在设计上是可选的。真可惜 :( 但老实说,我对打字稿印象深刻,所以我不能抱怨那么多
  • 拿?怎么样?

标签: typescript


【解决方案1】:

如果您知道参数的最大数量,则可以根据需要执行尽可能多的重载。

type Modification =
    { (arg1: any, lastArgument: SomeType): void } |
    { (arg1: any, arg2: any, lastArgument: SomeType): void } |
    { (arg1: any, arg2: any, arg3: any, lastArgument: SomeType): void };

【讨论】:

    【解决方案2】:

    您可以将第一个参数(SomeType 类型)作为可选参数,如下所示:

    interface SomeType {
        a: number; // just so it's not an empty definition
    }
    
    type Modification =
        { (first: SomeType, ...rest: (string | number)[]): void; }
        | { (...rest: (string | number)[]): void; }
    
    // fine
    const someModification1: Modification = (firstParam: string, second: number) => {}
    const someModification2: Modification = (third: SomeType, firstParam: string, second: number) => { }
    
    // error
    const someModification3: Modification = (firstParam: string, second: number, third: SomeType) => { }
    

    请注意,如果您对 args 使用 any[],那么这也将涵盖 SomeType arg。

    【讨论】:

    • 感谢您的回答,如果我可以将最后一个参数交换为第一个,我会但我不能,因为它是最后一个参数是设计上可选的,这实际上使事情变得更糟。我刚刚发现,如果你有一个函数类型接口,最后一个参数是可选的,如果没有可选参数,断言为函数类型的方法不会抛出错误
    • 例如interface SomeFuncType { (a: string, b?: number): void } 并且此断言不会引发错误:let func: SomeFuncType = (a) => {}
    • 哦,如果你断言的函数没有所有参数,打字稿实际上不会抛出任何错误
    • 我不明白你在说什么,或者为什么你不能将第一个参数作为可选的SomeType
    • 我更新了我的问题以解释我想要什么。不过,它有点在那里,请注意
    猜你喜欢
    • 2017-11-24
    • 2022-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    相关资源
    最近更新 更多