2

I have a backend model with some properties that I want to be able to send to the frontend with certain properties excluded. I'd like to use typing to help me ensure they have been excluded.

I tried this approach of having an interface for the model and then a restricted interface using Omit<> to exclude the property.

interface Thing {
    foo: string
    secret: string
}

interface RestrictedThing extends Omit<Base, "secret"> {}

const thing: Thing = { foo: "test", secret: "must_exclude_in_restricted"}

const restricted: RestrictedThing = { ...thing } //does not complain

Unfortunately, when using the spread operator, typescript doesn't warn that there are properties present that should not be part of RestrictedThing.

I discovered ts-essentials StrictOmit but it only checks that the properties passed in are valid so it doesn't fit the bill.

I also tried using typeof without success

declare var { bar, ...forRestricted }: Thing;
type RestrictedThing = typeof forRestricted;

Is there a way to safely create a copy of my Thing object that uses typing to exclude unwanted properties?

Other approaches also welcome.

2
  • • What's Base? What is bar? Could you edit to make sure this is a minimal reproducible example without typos or private/third-party code? It makes it hard to proceed if we have to debug the question to get to the starting point. • Assuming Base is a typo for Thing, this has nothing to do with the spread operator; this code has the same lack of error. What, specifically would spread be doing here? Commented Apr 7, 2024 at 12:20
  • 1
    (see prev comment) • Oh, maybe you think TS has runtime effects? It doesn't. The TS type system is erased. At best you can write a type that makes const r: Restricted = { ...thing } an error in TS, like this, but nothing will actually remove the property unless you do it yourself. TS types have no effect, whatsoever, on runtime behavior. So, are you looking for a type that prohibits secret? Or a line of runtime code that removes secret from an object? Please edit to clarify. Commented Apr 7, 2024 at 12:26

1 Answer 1

0

Unfortunately, TypeScript's type system doesn't currently support excess property checks on object literals resulting from a spread operation. This is a known limitation of TypeScript.

If you need to ensure that an object doesn't have certain properties, you'll need to manually check for those properties at runtime.

Use is operator to ensure the type is correct and within that method, delete the secret keys.

interface Thing {
  foo: string
  secret: string;
  secret2: string;
}
const restrictedKeys = ['secret','secret2'] as const;
interface RestrictedThing extends Omit<Thing, typeof restrictedKeys[number]> {}

const thing = {
  foo: "test",
  secret: "must_exclude_in_restricted"
};

const restricted: Partial<Thing> = { ...thing };

const cleanRestricted = (obj: Partial<Thing>): obj is RestrictedThing => {
  restrictedKeys.forEach(k => delete obj[k])
  return true;
};
if (cleanRestricted(restricted)) {
  // restricted is now really <RestrictedThing>
  restricted.secret = 'secret'; //throws error
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.