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' });
Answer from JJWesterkamp on Stack OverflowAn 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' });
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
Add exactly empty object ({} literal) type
Empty interface allow any object?
typescript - Empty interface allow any object? - Stack Overflow
typescript - How to instantiate an interface with an empty object? - Stack Overflow
I know this is a really basic question, and I've tried to look at similar questions and didn't understand it so I apologize.
I'm translating my JavaScript code to TypeScript, and have a lot of code that looks similar to this:
if (!user_dict.options) {
user_dict.options = {}
}This produces the error "property options does not exist on type {}" for both lines. How can I establish an empty object like this, if I don't know what type of variables will later be stored? I have hundreds of empty variable declarations like this, and I can't know at this point in the code the "type" of variable being stored later, so I don't understand how I'm supposed to handle this using TypeScript?
I have hundreds of empty variable declarations like this, and I can't know at this point in the code the "type" of variable being stored later,
You don't know what sort of data you're planning on putting in the variable?
"property options does not exist on type {}"
Do it basically tells you that user_dict type doesn’t contain ‘options’ property. You need to add it to user_dict type or interface. Or if you don’t have type for this object you’d better write it.
This behavior is intentional.
The excess property check is not performed when the target is an empty object type since it is rarely the intent to only allow empty objects.
Actually, you can assign {a: 1} to B, the other answers here are mostly wrong.
You have stumbled upon another slightly confusing quirk in TypeScript, namely that you can not directly assign an object literal to a type where the object literal contains other properties than the one specified in the type.
However, you can assign any existing instance of an object to a type, as long as it fulfill the type.
For example:
interface Animal {
LegCount: number;
}
let dog: Animal = { LegCount: 4, Fur: "Brown" }; // Nope
var myCat = { LegCount: 4, Fur: "Black" };
let theCat: Animal = myCat; // OK
This constraint is simply ignored whey you have a type that is empty.
Read more here and here.
A later answer from the Typescript team is available on GitHub.
Okay, interesting question.
Test Case 1:
interface A {};
interface B extends A {
b?: any;
}
const a: A = {a: 1};
console.log(a);
It passes, as A is an empty interface, whatever you dumb inside is going to return back. Works like a class Object
Test Case 2:
interface A {};
interface B extends A {
b?: any;
}
const a: A = {b: 1};
console.log(a);
Just changed the value a to b just to prove first test case. It passes.
Test Case 3:
interface A {};
interface B extends A {
b?: any;
}
const a: B = {a: 1};
console.log(a);
It fails, because there is no prop inside interface A or B that is named a
Test Case 4:
interface A {};
interface B extends A {
b?: any;
}
const a: B = {b: 1};
console.log(a);
It passes, as interface B has a prop named b
I hope this helps you understand.
PS: prop refers to property.
Take this as an analogy: Interface A is a empty house, dumb whatever you want. It wont utter a word. Interface B is a house in a colony, which means it needs behave specifically to size, shape and needs to stick to Interface A. Which means Interface B is not more a empty and is restricted with rules.
export default interface ConfigData {
languageCode : string
, numberOfRepeats : number
}Probably a basic thing for you guys to sort out. I'm thinking on initialization, allow TS to infer variable type, then enforce the interface as return type:
run() {
// data to be returned at end
const configData = {};
this.steps.forEach(async (configStep: WizardSteps): ConfigData => {
// capture answer
const rawUserResponse: string|void = await configStep.explain();
if (configStep.needsValidation) {
// loops until validated
const validatedInput: string = configStep.validatedInput(rawUserResponse);
if (configStep.hasSaveableData) {
// convert to k/v pair
const formattedForConfiguration = configStep.format(rawUserResponse);
// save to local object
Object.assign(configData, formattedForConfiguration);
}
}
})
return configData;
}Is this the proper pattern? If not, how should an interface enforce types on something that is initially set to one value and then mutated?
If you are creating the "modal" variable elsewhere, and want to tell TypeScript it will all be done, you would use:
declare const modal: IModal;
If you want to create a variable that will actually be an instance of IModal in TypeScript you will need to define it fully.
const modal: IModal = {
content: '',
form: '',
href: '',
$form: null,
$message: null,
$modal: null,
$submits: null
};
Or lie, with a type assertion, but you'll lost type safety as you will now get undefined in unexpected places, and possibly runtime errors, when accessing modal.content and so on (properties that the contract says will be there).
const modal = {} as IModal;
Example Class
class Modal implements IModal {
content: string;
form: string;
href: string;
$form: JQuery;
$message: JQuery;
$modal: JQuery;
$submits: JQuery;
}
const modal = new Modal();
You may think "hey that's really a duplication of the interface" - and you are correct. If the Modal class is the only implementation of the IModal interface you may want to delete the interface altogether and use...
const modal: Modal = new Modal();
Rather than
const modal: IModal = new Modal();
If you want an empty object of an interface, you can do just:
var modal = <IModal>{};
The advantage of using interfaces in lieu of classes for structuring data is that if you don't have any methods on the class, it will show in compiled JS as an empty method. Example:
class TestClass {
a: number;
b: string;
c: boolean;
}
compiles into
var TestClass = (function () {
function TestClass() {
}
return TestClass;
})();
which carries no value. Interfaces, on the other hand, don't show up in JS at all while still providing the benefits of data structuring and type checking.