20

I use TypeScript version 2.3.4. I want to write a function that accepts an object that must have specified fields. But this object should not contain any other fields. How can I achieve this?

Now this works only if I define object inline. But if I use another object with extra fields - the compiler will allow it. What is totally wrong.

Example:

function foo(arg: { a: string }) { // there is tons of fields actually
  // ...
}

foo ({a: "qwerty"}); // No Error - ok

foo ({a: "qwerty", b: 123}); // Error - ok

let bar = {
  a: "qwerty",
  b: 123
};

foo (bar); // No Error - NOT OK !!!

The same code can be writed with interfaces, classes, type declarations - it's the same problem.

Now I have to extract the fields from the object manually to make sure that there are no extra fields. But I can't spread this solution on ~1000 functions (I really need this) all over the code - it's too messy. I creating API wrapper and I need to ensure that there are no additional or wrong fields passed to the server.

2
  • Looks like it is intentional. See this issue and this for additional discussion. Commented Jun 20, 2017 at 7:09
  • Saravana, yeah, I read this, but there is no answer for my question in theese discussions. I think is will be better to avoid strictness for interfaces, but leave it for classes. Commented Jun 20, 2017 at 7:29

5 Answers 5

6

The feature you are asking for is known as "exact types".
It's being considered, that is, neither rejected nor accepted, and the discussion still goes on.

Sign up to request clarification or add additional context in comments.

Comments

3

Necromancing.
It's coming with typescript 2.4:

type foo = {
  a:string;
  b:number;
  opt?:string;
}


function test(obj:foo)
{}

test({ a:"", b:123, e:"produceError"});

And to enforce it's an object, if all parameters are optional:

function test(obj:foo & object)
{}

And if you want to pass either a string or a another object-type:

function test(obj: string | foo & object)
{}

Comments

2

This is how it works by design and I'm not sure you can work this around. See the docs for more info.

What you also do wrong - you cannot be 100% sure about what's sent to the server. As long as browser does not know anything about TS, some library can inject into any request whatever it needs with e.g. by overwriting XmlHttpRequest methods (this is what e.g. at least angular's zone.js does).

Another way to easily break your intentions is as simple as using <any> in front of any parameter you pass.

TypeScript is intended to improve your development process but I don't think it can be used for the needs like yours. This is usually covered by writing the proper tests.

1 Comment

Of course I'm know that TS compiled to JS where no classes or type checks! I need to secure my method from other developers in development process. This all about development. Real case example: codepen.io/HarryBurns/pen/LLWoVa.typescript
2

There "is" a way, but you have to implement it yourself. It's called a "User Defined Type Guard" and it looks like this:

interface Test {
    prop: number;
}

function isTest(arg: any): arg is Test {
    return arg && arg.prop && typeof(arg.prop) == 'number';
}

1 Comment

It's better to do with Reflection (see blog.wolksoftware.com/…), so it will be shorter, something like check<MyType>(myObject). Or, in my case it's pick<MyType>(myObject). Works like underscore/lodash pick function.
1

With conditional types it is possible to check if two types extend each other - kind of equality check for types. Below a possible solution:

type IsEqual<A,B> = A extends B ? B extends A ? true : false : false
type FooParams = { a: string }

function foo<A extends FooParams>(arg: IsEqual<A, FooParams> extends true ? A : never) {
  // ...
}

foo ({a: "qwerty"}); // No Error - ok

foo ({a: "qwerty", b: 123}); // Error - ok

let bar = {
  a: "qwerty",
  b: 123
};

foo (bar); // Error - ok

PLAYGROUND

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.