【问题标题】:Force a function to accept only object of a specific structure (in typescript / js)强制函数只接受特定结构的对象(在 typescript / js 中)
【发布时间】:2017-07-23 08:08:57
【问题描述】:

我知道 typescript 的一些优点是启用类型安全的功能 -
但是是否可以确保我的函数只能获取具有特定键的对象,或者换句话说 - 特定结构的对象?

我知道许多优雅的方法来测试嵌套键是否存在,例如 [this one][1] ,
我当然可以在我的函数开始时运行一个小检查 - 但我问这个的原因是因为我的函数将被许多其他程序员使用 - 我想确保他们能够理解他们应该插入什么输入来自函数的签名。

例子:

function printName(user){
    console.log(user.details.name); // I want to ensure details.name exist
}

我希望有一些功能,例如:

function (user : {details: {name : string}}){
    //same ...
}


[1]: https://stackoverflow.com/questions/2631001/javascript-test-for-existence-of-nested-object-key#answer-4034468 "this one"

【问题讨论】:

  • 我建议再次浏览 TS 文档。这是非常基本的。顺便说一句,您是否尝试过您提供的代码?发生了什么?另外,您能否澄清details 是唯一的属性,还是事先已知的几个属性之一?

标签: javascript typescript javascript-objects type-safety


【解决方案1】:
interface User {
    details:{name: string}
}

function printName(user:User){
    console.log(user.details.name); // I want to ensure details.name exist
}

【讨论】:

    【解决方案2】:

    这正是您想要的功能:

    function printName(user: { [key: string]: any, details: { [key: string]: any, name: string }}) {
        console.log(user.details.name)
    }
    

    允许任何属性并且需要details + name

    更清晰易读并防止意外更改:

    // oftentimes you put the following interfaces in extra files:
    interface Details {
        readonly [key: string]: any // = allow other properties than "name"*
        readonly name: string
    }
    interface User {
        readonly [key: string]: any // = allow other properties than "details"*
        readonly details: Details
    }
    // *) consider explicitly specifying them
    
    function printName(user: User) {
        console.log(user.details.name)
    }
    

    如果您知道其他开发人员可能会从纯 JavaScript 代码(不是 TypeScript 代码)调用您的函数,请使用以下代码:

    function printName(user: User) {
        const name = ((user || <User>{}).details || <Details>{}).name
        if(name == void 0) {
            console.error("user name missing")
        }
        console.log(name)
    }
    

    Code on TypeScript Playground

    【讨论】:

    • 你什么都没保证。 [key: string]: anyname: string 的直接超集,所以它被吞没了。你基本上已经输入了user: {[key: string]: any}
    • 我添加了一个 Playground 链接,您可以尝试一下。
    • 我会修改,在这种情况下,[key: string]: any 是多余的,因为这是从界面中隐含的。
    • 这不是多余的,因为对象中可能还有其他属性。如果明确指定对象的形状,可以省略[key: string]: any
    【解决方案3】:

    如果您想从特定属性中检索值,请使用 keyof,这将突出显示不正确的属性名称。

    您也可以使用 Object.keys 来检查属性是否存在。

    interface UserProps {
      name: string;
      age: number;
    }
    
    export class User {
      constructor(private data: UserProps) {}
    
      get(propName: keyof UserProps): string | number {
        const dataKeys = Object.keys(this.data);
        if (!dataKeys.includes(propName)) {
          throw Error(`Property ${propName} does not exists on user object`);
        }
        return this.data[propName];
      }
    }
    

    【讨论】:

      【解决方案4】:

      您可以使用typescript中的接口

      export interface Details{
        name:string,
        age: number
      }
      export interface User{
        details :  {
              [key: string]: Details
          };
      }
      
      function printName(user : User){}
      

      【讨论】:

      • 这不起作用,因为Details 接口没有直接嵌套在User 下面。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-30
      • 1970-01-01
      • 2017-08-21
      • 2011-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多