简体   繁体   English

强制函数只接受特定结构的对象(在 typescript / js 中)

[英]Force a function to accept only object of a specific structure (in typescript / js)

I know some of typescript's advantages are enabling type-safe functions -我知道打字稿的一些优点是启用类型安全功能 -
but is it possible to ensure my function can only get objects with specific keys, or in other words - objects of specific structure ?但是是否可以确保我的函数只能获取具有特定键的对象,或者换句话说 - 特定结构的对象?

I know of many elegant ways to test if a nested key exists, such as [this one][1] ,我知道许多优雅的方法来测试嵌套键是否存在,例如 [this one][1] ,
and I can of course run a small check at the beginning of my function - but the reason I'm asking this is because my function will be used by many other programmers - and I want to ensure they can understand what input they should insert just from the function's signature.我当然可以在我的函数的开头运行一个小检查 - 但我问这个的原因是因为我的函数将被许多其他程序员使用 - 我想确保他们能够理解他们应该插入什么输入从函数的签名。

Example:示例:

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

and I would wish to have some feature like:我希望有一些功能,例如:

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


[1]: https://stackoverflow.com/questions/2631001/javascript-test-for-existence-of-nested-object-key#answer-4034468 "this one"
interface User {
    details:{name: string}
}

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

This is exactly the feature you desire:这正是您想要的功能:

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

Allow any properties and require details + name .允许任何属性需要details + name

More legible and protected against unintentional changes:更清晰,并防止意外更改:

// 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)
}

And use the following code if you know other developers may call your function from plain JavaScript code (not TypeScript code):如果您知道其他开发人员可能会从纯 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 TypeScript Playground 上的代码

Use keyof if you want to retrieve a value from a specific property, this will highlight the incorrect property name.如果要从特定属性检索值,请使用 keyof,这将突出显示不正确的属性名称。

You can also use Object.keys to check if the property exists.您还可以使用 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];
  }
}

You can use interfaces in typescript您可以在打字稿中使用接口

export interface Details{
  name:string,
  age: number
}
export interface User{
  details :  {
        [key: string]: Details
    };
}

function printName(user : User){}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM