Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I getting an error "Object literal may only specify known properties"?

Tags:

typescript

I just upgraded from TypeScript 1.5 to the latest and I'm seeing an error in my code:

interface Options {    /* ... others ... */    callbackOnLocationHash?: boolean; }  function f(opts: Options) { /* ... */ }  //  Error: Object literal may only specify known properties, //     and 'callbackOnLoactionHash'does not exist in type 'Options'. f( { callbackOnLoactionHash: false }); 

Code looks fine to me. What's wrong?

(Alternative universe version: I recognize the typo, and I really did mean to write that. What should I do to remove the error?)

like image 756
Ryan Cavanaugh Avatar asked Aug 04 '15 17:08

Ryan Cavanaugh


People also ask

How do you declare a property within an object literal?

Object literals are defined using the following syntax rules: A colon separates property name[1] from value. A comma separates each name-value pair from the next. A comma after the last name-value pair is optional.

What is meant by object literal?

Object Literal. In plain English, an object literal is a comma-separated list of name-value pairs inside of curly braces. Those values can be properties and functions. Here's a snippet of an object literal with one property and one function.

How do you declare an object literal?

The object literal is a short form of creating an object. Define an object in the { } brackets with key:value pairs separated by a comma. The key would be the name of the property and the value will be a literal value or a function.

What character defines an object literal?

Object literals. An object literal is a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ( {} ).


1 Answers

As of TypeScript 1.6, properties in object literals that do not have a corresponding property in the type they're being assigned to are flagged as errors.

Usually this error means you have a bug (typically a typo) in your code, or in the definition file. The right fix in this case would be to fix the typo. In the question, the property callbackOnLoactionHash is incorrect and should have been callbackOnLocationHash (note the mis-spelling of "Location").

This change also required some updates in definition files, so you should get the latest version of the .d.ts for any libraries you're using.

Example:

interface TextOptions {     alignment?: string;     color?: string;     padding?: number; } function drawText(opts: TextOptions) { ... } drawText({ align: 'center' }); // Error, no property 'align' in 'TextOptions' 

But I meant to do that

There are a few cases where you may have intended to have extra properties in your object. Depending on what you're doing, there are several appropriate fixes

Type-checking only some properties

Sometimes you want to make sure a few things are present and of the correct type, but intend to have extra properties for whatever reason. Type assertions (<T>v or v as T) do not check for extra properties, so you can use them in place of a type annotation:

interface Options {     x?: string;     y?: number; }  // Error, no property 'z' in 'Options' let q1: Options = { x: 'foo', y: 32, z: 100 }; // OK let q2 = { x: 'foo', y: 32, z: 100 } as Options; // Still an error (good): let q3 = { x: 100, y: 32, z: 100 } as Options; 

These properties and maybe more

Some APIs take an object and dynamically iterate over its keys, but have 'special' keys that need to be of a certain type. Adding a string indexer to the type will disable extra property checking

Before

interface Model {   name: string; } function createModel(x: Model) { ... }  // Error createModel({name: 'hello', length: 100}); 

After

interface Model {   name: string;   [others: string]: any; } function createModel(x: Model) { ... }  // OK createModel({name: 'hello', length: 100}); 

This is a dog or a cat or a horse, not sure yet

interface Animal { move; } interface Dog extends Animal { woof; } interface Cat extends Animal { meow; } interface Horse extends Animal { neigh; }  let x: Animal; if(...) {   x = { move: 'doggy paddle', woof: 'bark' }; } else if(...) {   x = { move: 'catwalk', meow: 'mrar' }; } else {   x = { move: 'gallop', neigh: 'wilbur' }; } 

Two good solutions come to mind here

Specify a closed set for x

// Removes all errors let x: Dog|Cat|Horse; 

or Type assert each thing

// For each initialization   x = { move: 'doggy paddle', woof: 'bark' } as Dog; 

This type is sometimes open and sometimes not

A clean solution to the "data model" problem using intersection types:

interface DataModelOptions {   name?: string;   id?: number; } interface UserProperties {   [key: string]: any; } function createDataModel(model: DataModelOptions & UserProperties) {  /* ... */ } // findDataModel can only look up by name or id function findDataModel(model: DataModelOptions) {  /* ... */ } // OK createDataModel({name: 'my model', favoriteAnimal: 'cat' }); // Error, 'ID' is not correct (should be 'id') findDataModel({ ID: 32 }); 

See also https://github.com/Microsoft/TypeScript/issues/3755

like image 199
Ryan Cavanaugh Avatar answered Sep 24 '22 02:09

Ryan Cavanaugh