13

I'm trying to extend existing interface:

type ColDef = { field: string; }

so that I will limit field values only to actual properties of specified type:

interface TypeSafeColDef<T> extends ColDef {
   field: keyof T
}

but I'm getting:

Interface 'TypeSafeColDef' incorrectly extends interface 'ColDef'. Types of property 'field' are incompatible. Type 'keyof TRow | undefined' is not assignable to type 'string | undefined'. Type 'keyof TRow' is not assignable to type 'string | undefined'. Type 'string | number | symbol' is not assignable to type 'string | undefined'. Type 'number' is not assignable to type 'string | undefined'. Type 'keyof TRow' is not assignable to type 'string'. Type 'string | number | symbol' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'

I've tried following constraint, but no success

type StringKey = { [key: string]: any }

interface TypeSageColDef<TRow extends StringKey>
2
  • extends { [key: string]: any } behaves same as extends object for some reason (not limiting keys to be string only). Real question is why do you need extends ColDef? Do you have more properties in real example? Commented Jan 23, 2020 at 12:36
  • I need to extend ColDef because I want to get compiler error when invalid field is passed. I do not own ColDef, it is a 3rd party type definition. Commented Jan 23, 2020 at 12:44

1 Answer 1

16

Your last one comes quite close, we still need to extend ColDef and extract a string key type for field:

type ColDef = { field: string; }

interface TypeSafeColDef<T extends object> extends ColDef {
  field: Extract<keyof T, string>
}

// test
type T1 = TypeSafeColDef<{ a: string }> // { field: "a"; }

field now has type Extract<keyof T, string>, because keyof supports string | number | symbol property names since TS 2.9. There is a compiler option --keyofStringsOnly to disable this new behavior, if you don't want that.

A second alternative is to define a type alias to get rid of Extract. This works due to the nature of the intersection operator never provoking errors:

type TypeSafeColDefAlias<T extends object> = ColDef & {
  field: keyof T
}

Code sample

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

4 Comments

extends StringKey looks redundant if you're anyway doing Extract<keyof T, string>
yeah, StringKey is not needed in this case. I suggest to edit the answer and I will accept it
@Liero updated answer (and gave another possible alternative)
I needed to enforce string type for grid column helper. Here is how I did it export class GridColumnHelper<T> { ... createColumn(field: Extract<keyof T, string> ... }. This is instead of field: keyof T. Hope it helps someone.

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.