Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript initiate an empty interface object

Im building an app using angular 5 ( TS ), i got stuck trying to initiate an empty object of my interface.
So the only acceptable solution i have seen is this one:

article: Article = {} as Article;

Although its seems legit it doesn't work; trying to use article["something"] will fail because its just an empty object without any keys .

The result im seeking looks something like this:

export interface Article {
slug: string;
title: string;
description: string;
body: string;
tagList: string[];

after init:

article = { 'slug': '', 'title': '', 'description': '', body: '', tagList: '[]' }
like image 533
Alex Avatar asked Apr 09 '18 21:04

Alex


5 Answers

An interface does not define an initial value for actual objects, but defines the requirements an object must meet for it to be an implementation of that interface.

You should create a factory of some kind that creates objects of type Article, this could be as simple as this function:

const emptyArticle = (): Article => ({
    slug: '',
    title: '',
    description: '',
    body: '',
    tagList: [],
});

You could additionally create a function that accepts an object that is a Partial<Article> - as described here. This enables you to pass a subset of initial values to the function. This example uses emptyArticle defined above:

const createArticle = <T extends Partial<Article>>(initialValues: T): Article & T => {
    return Object.assign(emptyArticle(), initialValues);
};

// Initialize a new article with a certain slug:
createArticle({ slug: 'my-awesome-article' });
like image 86
JJWesterkamp Avatar answered Oct 20 '22 18:10

JJWesterkamp


Or more simply replace Interface to Class by setting default values like:

export class Article {
   slug: string = '';
   title: string = '';
   description: string = '';
   body: string = '';
   tagList: string[] = [];
}

When let article = new Article() it will already have properties with default values

like image 21
Yerkon Avatar answered Oct 20 '22 20:10

Yerkon


Interfaces (and types in general) are just a compile time construct to help the compiler validate our code, as such the type assertion you use ({} as Article) will do nothing more than to tell the compiler that empty object literal has that shape. If you want to have an 'empty' object for your interface, you will have to create it yourself:

interface Article {
    slug: string;
    title: string;
    description: string;
    body: string;
    tagList: string[];
}

function emptyArticle(): Article {
    return {
        slug: '',
        title: '',
        description: '',
        body: '',
        tagList: []
    }

}

The good news is that the compiler will warn you if you forget to add a default for any of the mandatory field.

Or if you want to make sure optional field are also specified you can create a mapped type that removes the optional from the fields.

type Mandatory<T> = { [P in keyof T]-?: T[P] };
function emptyArticle(): Mandatory<Article> {
    return {
        ....
    }

} 
like image 34
Titian Cernicova-Dragomir Avatar answered Oct 20 '22 18:10

Titian Cernicova-Dragomir


Here is another way to initialize. Worked for me:

const article: Article = ({} as any) as Article;
like image 5
DimaShah Avatar answered Oct 20 '22 19:10

DimaShah


When you want to initialize an object without properties, then have to declare it that it is valid without properties. Also the properties have to be optional:

export interface Article {
  slug?: string;
  title?: string;
  description?: string;
  body?: string;
  tagList?: string[];
}

when not you have to initialize the object as you mentioned already

article = { 'slug': '', 'title': '', 'description': '', body: '', tagList: '[]' }
like image 2
fastr.de Avatar answered Oct 20 '22 18:10

fastr.de