En TypeScript, ¿hay alguna razón para preferir const foo: Type={...} o const foo={ ... } as Type?
En TypeScript, hay dos maneras de declarar que una constante debe cumplir con una interfaz:
interface Foo { x: string; }
const HELLO: Foo = { x: 'hello' };
o
interface Foo { x: string; }
const HELLO = { x: 'hello' } as Foo;
Estos parecen tener el mismo efecto: TypeScript trata HELLO como si tuviera un tipo Foo, y asignarle cualquier miembro que no aparezca en interface Foo resulta en un error.
¿Hay alguna razón para preferir una forma sobre la otra? ¿Son exactamente equivalentes?
Respuesta #1
En tu ejemplo, la asignación resulta ser la misma. Sin embargo, la funcionalidad de tipar una variable como en tu primer ejemplo y hacer un cambio de tipo de tu variable, como en el segundo ejemplo, no son lo mismo.
Aquí hay un ejemplo extendido:
interface Foo { x: string; }
interface Foo2 extends Foo { y: string; }
// typing the variables
const hello: Foo = { x: 'hello' }; // works
const hello2: Foo2 = { x: 'hello', y: 'hello' }; // works
const hello3: Foo2 = { x: 'hello' }; // does not work because property 'y' is missing
// typecasting the variables
const hello4 = hello as Foo2; // works
const hello5 = hello2 as Foo2; // works
const hello6 = { x: 'hello' } as Foo2; // works
// typing the variables
const hello7: Foo = {}; // does not work because property 'x' is missing
const hello8: Foo2 = {}; // does not work because property 'y' is missing
// typecasting the variables
const hello9 = <Foo>{}; // works
const hello10 = <Foo2>{}; //works
// typing must match exact form, where typecasting does not, as long as interface is honored
const hello11: Foo = { x: 'hello', y: 'hello' }; // fails because of extra property 'y'
const hello12 = { x: 'hello', y: 'hello' } as Foo; // works
Como puedes ver, escribir el tipo de la variable funciona solo si el objeto asignado tiene una forma exactamente coincidente. El cambio de tipo de la variable funciona incluso si el objeto asignado no es válido, ya que esencialmente significa que le estás diciendo a TypeScript que te asegurarás de que lo sea en algún momento.. por ejemplo, si inicializas con un objeto no válido y luego, usando alguna lógica, estableces las propiedades faltantes restantes.
La conversión de tipos se puede realizar utilizando la palabra clave as o anteponiendo la variable asignada con <tipo>.
Respuesta #2
Esto es para Typescript 2.1.4. No estoy al tanto de diferencias en otras versiones.
En el primero, deberías obtener un error de compilación si hicieras esto:
interface Foo { x: string; }
const HELLO: Foo = { x:'hello', y: 'goodbye' }; // Will not compile.
En el segundo, esencialmente lo estás convirtiendo a la interfaz Foo, por lo que en lo que respecta a la compilación, esto es perfectamente válido.
interface Foo { x: string; }
const HELLO = { x:'hello', y: 'goodbye' } as Foo; // No compilation error.
const yValue = HELLO.y; // compilation error because "y" should not exist according to the interface
const yValue2 = (HELLO as any).y // suddenly works; yValue2 === "goodbye"
El primero no te permitirá crear el objeto con datos añadidos, por lo que puede prevenir errores tontos. El segundo te permitirá convertir un objeto ya creado que tenga los mismos valores que la interfaz. Luego puedes pasar ese objeto a otras funciones o clases como si fuera la interfaz. Esencialmente ocultará los valores adicionales.
