如果我想以编程方式将属性分配给 Javascript 中的对象,我会这样做:
var obj = {};
obj.prop = "value";
但在 TypeScript 中,这会产生错误:
“{}”类型的值上不存在属性“prop”
我应该如何将任何新属性分配给 TypeScript 中的对象?
如果我想以编程方式将属性分配给 Javascript 中的对象,我会这样做:
var obj = {};
obj.prop = "value";
但在 TypeScript 中,这会产生错误:
“{}”类型的值上不存在属性“prop”
我应该如何将任何新属性分配给 TypeScript 中的对象?
可以表示obj
为any
,但这违背了使用打字稿的全部目的。obj = {}
暗示obj
是一个Object
. 将其标记为any
没有意义。为了实现所需的一致性,可以如下定义接口。
interface LooseObject {
[key: string]: any
}
var obj: LooseObject = {};
或使其紧凑:
var obj: {[k: string]: any} = {};
LooseObject
可以接受任何字符串作为键和any
类型作为值的字段。
obj.prop = "value";
obj.prop2 = 88;
此解决方案的真正优雅之处在于您可以在界面中包含类型安全字段。
interface MyType {
typesafeProp1?: number,
requiredProp1: string,
[key: string]: any
}
var obj: MyType ;
obj = { requiredProp1: "foo"}; // valid
obj = {} // error. 'requiredProp1' is missing
obj.typesafeProp1 = "bar" // error. typesafeProp1 should be a number
obj.prop = "value";
obj.prop2 = 88;
Record<Keys,Type>
实用类型更新(2020 年 8 月):@transang 在评论中提出了这一点
Record<Keys,Type>
是打字稿中的实用程序类型。对于属性名称未知的键值对,它是一种更简洁的替代方案。值得注意的是where和are genericsRecord<Keys,Type>
的命名别名。IMO,这在这里值得一提{[k: Keys]: Type}
Keys
Type
为了比较,
var obj: {[k: string]: any} = {};
变成
var obj: Record<string,any> = {}
MyType
现在可以通过扩展 Record 类型来定义
interface MyType extends Record<string,any> {
typesafeProp1?: number,
requiredProp1: string,
}
虽然这回答了原始问题,但@GreeneCreations 的答案可能会为如何解决问题提供另一种观点。
或者一口气:
var obj:any = {}
obj.prop = 5;
当您的对象具有特定类型时,此解决方案很有用。就像将对象获取到其他来源时一样。
let user: User = new User();
(user as any).otherProperty = 'hello';
//user did not lose its type here.
我倾向于放在any
另一边,即var foo:IFoo = <any>{};
这样的东西仍然是类型安全的:
interface IFoo{
bar:string;
baz:string;
boo:string;
}
// How I tend to intialize
var foo:IFoo = <any>{};
foo.bar = "asdf";
foo.baz = "boo";
foo.boo = "boo";
// the following is an error,
// so you haven't lost type safety
foo.bar = 123;
或者,您可以将这些属性标记为可选:
interface IFoo{
bar?:string;
baz?:string;
boo?:string;
}
// Now your simple initialization works
var foo:IFoo = {};
尽管编译器抱怨它仍应按您的要求输出它。但是,这将起作用。
const s = {};
s['prop'] = true;
另一种选择是将属性作为集合访问:
var obj = {};
obj['prop'] = "value";
我很惊讶没有一个答案引用 Object.assign,因为这是我在考虑 JavaScript 中的“组合”时使用的技术。
它在 TypeScript 中按预期工作:
interface IExisting {
userName: string
}
interface INewStuff {
email: string
}
const existingObject: IExisting = {
userName: "jsmith"
}
const objectWithAllProps: IExisting & INewStuff = Object.assign({}, existingObject, {
email: "jsmith@someplace.com"
})
console.log(objectWithAllProps.email); // jsmith@someplace.com
好处
any
类型&
在声明 的类型时objectWithAllProps
由需要注意的事项
existingObject
保持不变,因此没有email
属性。对于大多数函数式程序员来说,这是一件好事,因为结果是唯一的新变化)。您可以使用扩展运算符基于旧对象创建新对象
interface MyObject {
prop1: string;
}
const myObj: MyObject = {
prop1: 'foo',
}
const newObj = {
...myObj,
prop2: 'bar',
}
console.log(newObj.prop2); // 'bar'
TypeScript 将推断原始对象的所有字段,VSCode 将执行自动补全等。
情况1:
var car = {type: "BMW", model: "i8", color: "white"};
car['owner'] = "ibrahim"; // You can add a property:
案例二:
var car:any = {type: "BMW", model: "i8", color: "white"};
car.owner = "ibrahim"; // You can set a property: use any type
你可以使用这个:
this.model = Object.assign(this.model, { newProp: 0 });
因为你不能这样做:
obj.prop = 'value';
如果你的 TS 编译器和你的 linter 不严格你,你可以这样写:
obj['prop'] = 'value';
如果您的 TS 编译器或 linter 是严格的,另一个答案是类型转换:
var obj = {};
obj = obj as unknown as { prop: string };
obj.prop = "value";
最简单的将遵循
const obj = <any>{};
obj.prop1 = "value";
obj.prop2 = "another value"
这是 的一个特殊版本Object.assign
,它会随着每个属性的变化自动调整变量类型。不需要额外的变量、类型断言、显式类型或对象副本:
function assign<T, U>(target: T, source: U): asserts target is T & U {
Object.assign(target, source)
}
const obj = {};
assign(obj, { prop1: "foo" })
// const obj now has type { prop1: string; }
obj.prop1 // string
assign(obj, { prop2: 42 })
// const obj now has type { prop1: string; prop2: number; }
obj.prop2 // number
// const obj: { prop1: "foo", prop2: 42 }
要保证类型是一个Object
(即键值对),请使用:
const obj: {[x: string]: any} = {}
obj.prop = 'cool beans'
可以通过以下方式将成员添加到现有对象
interface IEnhancedPromise<T> extends Promise<T> {
sayHello(): void;
}
const p = Promise.resolve("Peter");
const enhancedPromise = p as IEnhancedPromise<string>;
enhancedPromise.sayHello = () => enhancedPromise.then(value => console.info("Hello " + value));
// eventually prints "Hello Peter"
enhancedPromise.sayHello();
最佳做法是使用安全输入,我建议您:
interface customObject extends MyObject {
newProp: string;
newProp2: number;
}
通过将其类型转换为“any”,将任何新属性存储在任何类型的对象上:
var extend = <any>myObject;
extend.NewProperty = anotherObject;
稍后您可以通过将扩展对象转换回“任何”来检索它:
var extendedObject = <any>myObject;
var anotherObject = <AnotherObjectType>extendedObject.NewProperty;
要保留您以前的类型,请将您的对象临时转换为任何
var obj = {}
(<any>obj).prop = 5;
新的动态属性仅在您使用强制转换时可用:
var a = obj.prop; ==> Will generate a compiler error
var b = (<any>obj).prop; ==> Will assign 5 to b with no error;
为 Angular 扩展 @jmvtrinidad 解决方案,
当使用已经存在的类型对象时,这是添加新属性的方法。
let user: User = new User();
(user as any).otherProperty = 'hello';
//user did not lose its type here.
现在,如果您想otherProperty
在 html 端使用,这就是您所需要的:
<div *ngIf="$any(user).otherProperty">
...
...
</div>
Angular 编译器将类型$any()
转换视为any
类型转换,就像在 TypeScript中使用<any>
或转换时一样as any
。
您可以添加此声明以使警告静音。
declare var obj: any;
在 TypeScript 中为对象动态分配属性。
要做到这一点你只需要像这样使用打字稿接口:
interface IValue {
prop1: string;
prop2: string;
}
interface IType {
[code: string]: IValue;
}
你可以这样使用它
var obj: IType = {};
obj['code1'] = {
prop1: 'prop 1 value',
prop2: 'prop 2 value'
};
唯一完全类型安全的解决方案是这个,但有点罗嗦,并迫使您创建多个对象。
如果您必须先创建一个空对象,请选择这两种解决方案之一。请记住,每次使用 时as
,您都会失去安全感。
的类型在内部object
是安全getObject
的,这意味着object.a
将是类型string | undefined
interface Example {
a: string;
b: number;
}
function getObject() {
const object: Partial<Example> = {};
object.a = 'one';
object.b = 1;
return object as Example;
}
的类型在内部object
是不安全getObject
的,这意味着即使在分配之前object.a
也是类型。string
interface Example {
a: string;
b: number;
}
function getObject() {
const object = {} as Example;
object.a = 'one';
object.b = 1;
return object;
}
如果你使用的是 Typescript,想必你想使用类型安全;在这种情况下,裸对象和“任何”被反指示。
最好不要使用 Object 或 {},而是使用一些命名类型;或者您可能正在使用具有特定类型的 API,您需要使用自己的字段进行扩展。我发现这个工作:
class Given { ... } // API specified fields; or maybe it's just Object {}
interface PropAble extends Given {
props?: string; // you can cast any Given to this and set .props
// '?' indicates that the field is optional
}
let g:Given = getTheGivenObject();
(g as PropAble).props = "value for my new field";
// to avoid constantly casting:
let k:PropAble = getTheGivenObject();
k.props = "value for props";
试试这个:
export interface QueryParams {
page?: number,
limit?: number,
name?: string,
sort?: string,
direction?: string
}
然后使用它
const query = {
name: 'abc'
}
query.page = 1
我在尝试对充当状态存储的对象进行部分更新时遇到了这个问题。
type State = {
foo: string;
bar: string;
baz: string;
};
const newState = { foo: 'abc' };
if (someCondition) {
newState.bar = 'xyz'
}
setState(newState);
在这种情况下,最好的解决方案是使用Partial<T>
. 它使用?
令牌使提供的类型上的所有属性都是可选的。在更具体的 SO 主题中阅读有关它的更多信息,关于将类型上的所有属性设为 optional。
这是我解决它的方法Partial<T>
:
type State = {
foo: string;
bar: string;
baz: string;
};
const newState: Partial<State> = { foo: 'abc' };
if (someCondition) {
newState.bar = 'xyz';
}
setState(newState);
这类似于 fregante 在他们的回答中描述的内容,但我想为这个特定的用例(这在前端应用程序中很常见)画出更清晰的画面。