TLDR; VERSION
Edit, I have added a Playground, Link at the bottom
I have an array ob objects in TypeScrip
The first problem I see is that your type annotations of infoConverter
as Converter<string>
and pressureConverter
as Converter<number>
are too wide. The compiler will dutifully forget that infoConverter.name
is "info"
, and instead will use the type annotation that says it is a string
.
I think you will get closer to what you want by just using type inference and a const assertion to get the narrowest possible types for your converter instances:
const infoConverter = {
name: "info",
uuid: "180a",
decode: (v: Buffer) => v.toString()
} as const;
const pressureConverter = {
name: "pressure",
uuid: "1810",
decode: (v: Buffer) => v / 1024
} as const;
const converters = [infoConverter, pressureConverter] as const;
At this point there's no guarantee that the elements of converters
conform to your Converter
interface, but you can make sure that any functions that accept converters
or types that accept typeof converters
are constrained to Converter<any>[]
and you'll get an error there if converters
has a mistake.
So let's look at those two type functions you want... given an array of Converter
types, get the list of name
s, and a mapping of name
to value
type. How about:
type Names<C extends ReadonlyArray<Converter<any>>> = C[number]["name"];
type Value<
C extends ReadonlyArray<Converter<any>>,
N extends Names<C>
> = Extract<C[number], { name: N }> extends Converter<infer V> ? V : never;
Note that I constrain C
to ReadonlyArray<Converter<any>>
and not Array<Converter<any>>
... this is a looser constraint (the Array
interface is an extension of the ReadonlyArray
interface; every Array
is a ReadonlyArray
but not vice versa; the naming is perhaps a bit misleading; maybe it should be ReadableAndWritableArray
for Array
and ReadableArray
for ReadonlyArray
... but I digress). That's so that C
will accept typeof converters
, which is a readonly tuple.
Anyway, the Names
type alias looks up the "name"
property type from the number
-indexed elements of the C
array. And the Value
type alias Extracts the elements of C
that have a name
property matching N
, and then infers the value type from it.
Does it work?
type TheNames = Names<typeof converters>; // "info" | "pressure"
type InfoValue = Value<typeof converters, "info">; // string
type PressureValue = Value<typeof converters, "pressure">; // number
Looks good to me. Note that the above lines have no compiler errors, so the converters
object must be correctly meeting the constraint of being a (possibly readonly) array of Converter
elements.
Hopefully you can use this to get your expanded example code working. Good luck!
Link to code