简体   繁体   中英

How can I specify a typed object literal in TypeScript?

Is there a way to make a typed object literal directly?

By directly I mean without having to assign it to a variable which is type annotated.

For example, I know I can do it like this:

export interface BaseInfo { value: number; }

export interface MyInfo extends BaseInfo { name: string; }

function testA(): BaseInfo = {
   const result: MyInfo = { value: 1, name: 'Hey!' };
   return result;
}

I also can do it like this:

function testB(): BaseInfo = {
   return { value: 1, name: 'Hey!' };
}

But what I need is something like:

function testC(): BaseInfo = {
   return { value: 1, name: 'Hey!' }: MyInfo; // <--- doesn't work
}

Or like this:

function testD(): BaseInfo = {
   return MyInfo: { value: 1, name: 'Hey!' }; // <--- doesn't work
}

Intellisense for members of object literals is provided by the contextual type (see section 4.19 of the spec) of the expression.

You can acquire a contextual type in a variety of ways. Some of the most common places where a contextual type is applied are:

  • The initializer of a variable with a type annotation
  • The expression in a return statement in a function or getter with a return type annotation
  • The expression in a type assertion expression ( <T>expr )

In your example, you can use a type assertion to force your object literal to have a contextual type:

function testB() {
   return <IMyInfo>{ name: 'Hey!' };
}

Answer is to use the identity function:

function to<T>(value: T): T { return value; }
const instance = to<MyInfo>({
    value: 1,
    name: 'Hey!',
});

there should be no performance impact for an unnecessary call the to function, it should be optimized away by the JIT compiler

Remember that that interfaces follow duck typing: if an object looks like it matches the interface, it does match the interface.

So

function testB(): IBaseInfo = {
   return { name: 'Hey!' };
}

is exactly the same as

function testA(): IBaseInfo = {
   var result: IMyInfo = { name: 'Hey!' };
   return result;
}

Either way, the returned object looks like an IMyInfo, so it is an IMyInfo. Nothing that happens inside the function affects what interfaces it matches.

However, in your examples, the return value of the function is IBaseInfo, so the compiler and intellisense will assume that the object is just an IBaseInfo. if you want the caller of the function to know that the return value is an IMyInfo, you need to make the return value of the function IMyInfo:

function testB(): IMyInfo = {
   return { name: 'Hey!' };
}

or using type inference, simply

function testB() = {
   return { name: 'Hey!' };
}

To be really type-safe there are these ways:

Example interface:

interface IFoo {
  firstName: string;
  lastName: string;
}

specify the function result type

function useResultType(): IFoo {
  return {
    firstName: 'mars'
    // compile error, when lastName is missing
    // , lastName: 'xx'
  };
}

return a constant

function resultVariable() {
  const result: IFoo = {
    firstName: 'mars'
    // compile error, when lastName is missing
    // , lastName: 'xx'
  };
  return result;
}

use a generic identity function (note: rxjs has an identity function)

function ident<T>(value: T): T {
  return value;
}
function identityFunction() {
  return ident<IFoo>({
    firstName: 'mars'
    // compile error, when lastName is missing
    // , lastName: 'xx'
  });
}

when you just use type assertions - the compiler will not show an error when you return any other type (eg in the examples, I "forgot" the lastName member)

function asCast() {
  return {
      firstName: 'mars'
    // NO error
  } as IFoo;
}

function cast() {
  return <IFoo>{
      firstName: 'mars'
    // NO error
  };
}

you can check the examples in the Typescript Playground

Your first and second examples fail, so yo can't do that. :)

Pretty sure you don't have to specify any types on your literal. As long as your literal meets the interface requirements, you're good.

interface IMyInfo { name: string; }
var asdf = {
   name: "test"
}

var qwer: IMyInfo = asdf;

If you want intellisense, you have to do something like:

在此处输入图像描述

Or maybe this is what you're looking for. Intellisense works here, at least on the playground.

在此处输入图像描述

Or maybe this. :)

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM