#How to restrict an object type which has a template string pattern index signature?

26 messages · Page 1 of 1 (latest)

trail river
#
type Foo = { [key in `prefix${string}`]: number };
   
const bar = { test: 1 };

const foo: Foo = bar; // I want an error here

The project uses JSDoc comments and an index.d.ts file.
I have read https://github.com/microsoft/TypeScript/issues/12936 and couldn't find an utility that worked.
i.e. it should set all other properties to never and work when assigning a variable—not an object literal.

GitHub

This is a proposal to enable a syntax for exact types. A similar feature can be seen in Flow (https://flowtype.org/docs/objects.html#exact-object-types), but I would like to propose it as a feature...

tender cosmos
#

yeah you'd need exact types for this

#

test isn't prefix${string}, so it's not checked

trail river
#

I know that but even import type { Exact } from 'type-fest'; doesn't work.

tender cosmos
#

ts doesn't have true exact types

#

this is simply how subtyping works

#

you only specify prefix${string}, that's checked to be valued as number
anything else is ignored

trail river
#

There's something wrong with what you are saying because if I replace type Foo = { [key in `prefix${string}`]: number }; by type Foo = { [key in 'prefix']: number }; it suddenly works.
i.e. Property 'prefix' is missing in type '{ test: number; }' but required in type 'Foo'.

#

Why would it work for strings but not for template string patterns?

tender cosmos
#

that's warning about an missing property, not an excess property

#

that doesn't solve your original issue

#

it's still not gonna warn about the excess test

#

with prefix${string}, that's indefinite, many such strings could fulfill that. it acts like an index signature: for each key that matches prefix${string}, it must be number, but it doesn't require that such a property exists

#

with key in "prefix", that just turns into a regular property

#

it has the same effect as if you had type Foo = { prefix: number }

trail river
#

Indeed, I have 2 demands:

  1. forbid extension of the object (using types)
  2. find no more than one property that matches the pattern
tender cosmos
#

neither of those are really possible with assignability rules

#

you could use a validator type

#

but honestly i'd consider redesigning

trail river
#

If that's true, that's reassuring and depressing.

tender cosmos
#

both of those are kinda just not how polymorphism work

#

the second one is kinda an extension of the first

type Foo<T extends string> = { [K in `pfx-${T}`]: number }
```now `T` must be a 1-member union but it still doesn't restrict having other props
trail river
#

Ill use type Foo = { [key in `a${string}` | `b${string}`]: Bar; }; for now.
It prevents indexability of unmatched properties, that's better than nothing.
Ill leave the question unresolved for now. Thanks for the help though.

tender cosmos
#

again do consider redesigning into something that.. makes more sense, tbh
if you can only have one key that matches, then why make it an object to begin with

trail river
#

It's an existing object of a public API that won't be removed which keys were just string. I was trying to restrict the keys to match our conventions.
i.e. all our properties must start with 2 type of strings
I am not designing I am enhancing/refactoring.

tender cosmos
#

good luck then