DEV Community

Cover image for TypeScript: Creating a Dynamic Interface
bob.ts
bob.ts

Posted on

24 3

TypeScript: Creating a Dynamic Interface

During my time as a developer I've created a lot of "typed" code. One particular issue has come up repeatedly and I finally had a moment of clarity.

The Problem

Whenever I write something like this ...

export interface ConfigType {
  type: string;
}

export interface DataModel {
  config: ConfigType; // ERROR HERE
  [key: string]: string;
}
Enter fullscreen mode Exit fullscreen mode

... I get the following error on the commented line above.

Property 'config' of type 'ConfigType' is not assignable to 'string' index type 'string'.

The issue is that the [key: string]: string; line gets enforced on all key/value pairs on the interface.

I've seen something like the following ...

export interface Person {
  id: number;
  firstname: string;
  lastname: string;
  [key: string]: string | number;
}
Enter fullscreen mode Exit fullscreen mode

... and this code does not present an error. This is because the[key: string]: string; line gets enforced on all key/value pairs on the interface and they are string or number.

I came up with two approaches to solving the issue listed below. I think the first is the better approach, but I will list both for consistency.

The Type Approach

This approach seems much cleaner, creating a new data type that has the fixed and dynamic portions ANDed together.

export interface ConfigType {
  type: string;
}

export type DataModel = {
  config: ConfigType;
} & {
  [key: string]: string;
};
Enter fullscreen mode Exit fullscreen mode

The Union Approach

The following code is another resolution.

export interface ConfigType {
  type: string;
}

export interface DataModel {
  config: ConfigType;
  [key: string]: string | ConfigType;
}
Enter fullscreen mode Exit fullscreen mode

This approach has the "issue" that a new "key" could be used with another ConfigType.

Conclusion

As I said, I think the first approach (the Type Approach) is the better of the two.

If anyone has another or better pattern, please let me know.

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (4)

Collapse
 
mondal10 profile image
Amit Mondal

Thanks, this saved my day 🙌

Collapse
 
rfornal profile image
bob.ts

Glad it helped!

Collapse
 
nirekcuf profile image
nirekcuf • Edited

Not sure if this is what your going for, but I did something like

type Implements< T, R extends T > = R;

then

type myInterface= Implements<{ [key: string]: unknown }, {config:ConfigType}>

Collapse
 
jansendev profile image
JhonatanSegura Galindo

Thanks 👌

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay