23

Essentially I want to ensure that an object argument contains all of the required properties, but can contain any other properties it wants. For example:

function foo(bar: { baz: number }) : number {
    return bar.baz;
}

foo({ baz: 1, other: 2 });

But this results in:

Object literal may only specify known properties, and 'other' does not exist in type '{ baz: number; }'.
Lucas
  • 11,997
  • 7
  • 62
  • 114

4 Answers4

42

Yes, you can. Try this:

interface IBaz {
    baz: number;
    [key: string]: any;
}

function foo(bar: IBaz) : number {
    return bar.baz;
}

foo({ baz: 1, other: 2 });
Hoang Hiep
  • 1,390
  • 4
  • 11
  • 17
  • 2
    I was initially thinking this, but wanted inline... (and for some reason i screwed up the [key: string] part using parens instead of square brackets)... – Lucas Mar 10 '17 at 17:20
17

Well, i hate answering my own questions, but the other answers inspired a little thought... This works:

function foo<T extends { baz: number }>(bar: T): void {
    console.log(bar.baz);
}

foo({baz: 1, other: 2});
Lucas
  • 11,997
  • 7
  • 62
  • 114
  • This looks like you have set it up so the function takes a type argument but you don't give it a type argument. Do you mind explaining a bit what you are doing here? Thank you. – 1252748 Mar 08 '21 at 15:14
6

If the known fields are coming from a generic type the way to allow wildcards is with T & {[key: string]: unknown}, any fields that are known must fit with the type's constraints and other fields are allowed (and considered type unknown)

Here is a sample:

type WithWildcards<T> = T & { [key: string]: unknown };

function test(foo: WithWildcards<{baz: number}>) {}

test({ baz: 1 }); // works
test({ baz: 1, other: 4 }); // works
test({ baz: '', other: 4 }); // fails since baz isn't a number

Then if you have a generic type T you can allow wildcard fields with WithWildCards<T>

Tadhg McDonald-Jensen
  • 17,001
  • 3
  • 29
  • 51
2

This can be most easily accomplished by defining a type definition for the the function parameter. Here's an example with inline type definition:

function foo(bar: { baz: number }) : number {
    return bar.baz;
}

const obj = { baz: 1, other: 2 };

foo(obj);
Steven Barnett
  • 2,318
  • 2
  • 19
  • 11
  • 1
    this one seems to result in another msg that is like this: Type ... has no properties in common with type '...'p using typescript 2.3.4 – Jun711 Aug 08 '18 at 19:33
  • How does this work? If you put the object inline it doesn't work. – 1252748 Mar 08 '21 at 15:13
  • It's an inline type definition, not an inline object. Runs fine in [TS Playground](https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABMOcAUAjAhgJwFyIDei2AXgWCALYYCmOiAvgJSIXV0OEBQifiOWlBA4k2HADoyAbm6Nu3CAgDOURHAwArRAF4iJLOUQBGADTqoAC3oEATE1mKVcADa0JLuAHM0KdBs1mZmkgA). – Steven Barnett Mar 08 '21 at 21:28