typescript 打字稿接口属性到字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29600539/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Typescript interface property to string
提问by Antoine ESTEVE
Question/Answer - Update 2019
问题/答案 - 2019 年更新
This questions was asked 5 years ago, and I had very little understanding of Typescript! I don't want to remove it because there is still some people reading this post.
这个问题是5年前问的,我对Typescript了解很少!我不想删除它,因为还有人在阅读这篇文章。
If you have a function that takes an object and a property of this object as parameter, you have a lot of options:
如果您有一个将对象和该对象的属性作为参数的函数,那么您有很多选择:
const foo = <T extends object>(object: T, property: keyof T) => {
// You can use object[property] here
};
// OR
const bar = <TKey extends string>(
object: Record<TKey, unknown>,
property: TKey,
) => {
// You can use object[property] here
};
// ...
Don't use this question answers please!Typescript will automatically tell you that there is an error if you rename the property at some point.
请不要使用此问题的答案!如果您在某个时候重命名该属性,Typescript 会自动告诉您存在错误。
Original question (2014)
原始问题 (2014)
Objective
客观的
I have an interface TypeScript :
我有一个接口 TypeScript :
interface IInterface{
id: number;
name: string;
}
I have some methods which take in entry the name of a property (string).
我有一些方法可以输入属性的名称(字符串)。
Ex:
例如:
var methodX = ( property: string, object: any ) => {
// use object[property]
};
My problem is that when i call methodX
, I have to write the property name in string.
我的问题是,当我打电话时methodX
,我必须在字符串中写入属性名称。
Ex :methodX("name", objectX);
where objectX implements IInterface
例如:methodX("name", objectX);
objectX 实现 IInterface
But this is BAD: If i rename a property (let's say i want to rename name
to lastname
) i will have to update manually all my code.
但这很糟糕:如果我重命名一个属性(假设我想重命名name
为lastname
),我将不得不手动更新我的所有代码。
And I don't want this dependency.
我不想要这种依赖。
As typescript interfaces have no JS implementations, I don't see how I could not use string.
由于打字稿接口没有 JS 实现,我不知道我怎么不能使用字符串。
I want to have something like : methodX(IInterface.name.propertytoString(), objectX);
我想要类似的东西: methodX(IInterface.name.propertytoString(), objectX);
I'm pretty new to JS, do you see an alternative ?
我对 JS 很陌生,你有没有其他选择?
(Optional) More details :Why do I need to pass properties as parameter, and why I don't use a generic method ?
(可选)更多细节:为什么我需要将属性作为参数传递,为什么我不使用泛型方法?
I use methods that link data :
我使用链接数据的方法:
linkData = <TA, TB>(
inputList: TA[],
inputId: string,
inputPlace: string,
outputList: TB[],
outputId: string ) => {
var mapDestinationItemId: any = {};
var i: number;
for ( i = 0; i < outputList.length; ++i ) {
mapDestinationItemId[outputList[i][outputId]] = outputList[i];
}
var itemDestination, itemSource;
for ( i = 0; i < inputList.length; ++i ) {
itemDestination = inputList[i];
itemSource = mapDestinationItemId[itemDestination[inputId]];
if ( itemSource ) {
itemDestination[inputPlace] = itemSource;
}
}
};
But TA and TB can have a lot of different ids. So i don't see how to make it more generic.
但是 TA 和 TB 可以有很多不同的 ID。所以我不知道如何使它更通用。
采纳答案by Antoine ESTEVE
Update 2019: This answer is outdated, please look at the update added directly into the question.
2019 年更新:此答案已过时,请查看直接添加到问题中的更新。
basaratanswer is a good idea, but it doesn't work with interfaces.
basarat答案是个好主意,但它不适用于接口。
You can'twrite methodX(interfacePropertyToString(()=>interfaceX.porpertyname), objectX)
because interfaceX
is not an object.
你不能写,methodX(interfacePropertyToString(()=>interfaceX.porpertyname), objectX)
因为interfaceX
它不是一个对象。
Interfaces are abstractions and they are used only for TypeScript, they doesn't exist in Javascript.
接口是抽象的,它们仅用于 TypeScript,它们不存在于 Javascript 中。
But thanks to his answer i found out the solution : using a parameter in the method.
但是由于他的回答,我找到了解决方案:在方法中使用参数。
Finally we have :
最后我们有:
interfacePropertyToString = ( property: (object: any) => void ) => {
var chaine = property.toString();
var arr = chaine.match( /[\s\S]*{[\s\S]*\.([^\.; ]*)[ ;\n]*}/ );
return arr[1];
};
We have to use [\s\S]
to be able to match on multilines because Typescript convert (object: Interface) => {object.code;}
to a multiline function.
我们必须使用[\s\S]
才能在多行上进行匹配,因为 Typescript 转换(object: Interface) => {object.code;}
为多行函数。
Now you can use it as you want :
现在你可以随意使用它:
interfacePropertyToString(( o: Interface ) => { o.interfaceProperty});
interfacePropertyToString( function ( o: Interface ) { o.interfaceProperty});
回答by basarat
You could write a function to parse the body of a function to find the name e.g.:
您可以编写一个函数来解析函数体以查找名称,例如:
methodX(getName(()=>something.name), objectX)
Where getName
will do a toString
on the function body to get a string of the form "function(){return something.name}"
and then parse it to get "name"
.
WheregetName
将toString
在函数体上执行 a以获取表单的字符串,"function(){return something.name}"
然后对其进行解析以获取"name"
.
Note: however this has a tendency to break depending upon how you minify it.
注意:然而,这有一种破坏的趋势,这取决于你如何缩小它。
回答by BrightShadow
I've changed basaratcode a little bit, so we can use it as generic:
我稍微改变了basarat代码,因此我们可以将其用作通用代码:
const P = <T>( property: (object: T) => void ) => {
const chaine = property.toString();
const arr = chaine.match( /[\s\S]*{[\s\S]*\.([^\.; ]*)[ ;\n]*}/ );
return arr[1];
};
And example usage:
和示例用法:
console.log(P<MyInterface>(p => p.propertyName));
回答by plinyar
Somewhat related problem - how to get/set a value to a property path. I wrote two classes for that:
有点相关的问题 - 如何获取/设置属性路径的值。我为此写了两个类:
export class PropertyPath {
static paths = new Map<string, PropertyPath>()
static get<T, P>(lambda: (prop:T) => P) : PropertyPath {
const funcBody = lambda.toString();
var ret : PropertyPath = this.paths[funcBody];
if (!ret) {
const matches = funcBody.match( /(?:return[\s]+)(?:\w+\.)((?:\.?\w+)+)/ ); //first prop ignores
var path = matches[1];
ret = new PropertyPath(path.split("."));
this.paths[funcBody] = ret;
}
return ret;
};
path : Array<string>
constructor(path : Array<string>) {
this.path = path
}
getValue( context : any) {
const me = this;
var v : any;
return this.path.reduce( (previous, current, i, path) => {
try {
return previous[current];
}
catch (e) {
throw {
message : `Error getting value by path. Path: '${path.join(".")}'. Token: '${current}'(${i})`,
innerException: e
};
}
}, context)
}
setValue( context : any, value : any) {
const me = this;
var v : any;
this.path.reduce( (previous, current, i, path) => {
try {
if (i == path.length - 1) {
previous[current] = value
}
return previous[current];
}
catch (e) {
throw {
message : `Error setting value by path. Path: '${path.join(".")}'. Token: '${current}'(${i}). Value: ${value}`,
innerException: e
};
}
}, context)
}
}
Example of usage:
用法示例:
var p = PropertyPath.get((data:Data) => data.person.middleName)
var v = p.getValue(data)
p.setValue(data, newValue)
Some sugar over it:
加点糖:
export class PropertyPathContexted {
static get<T, P>(obj : T, lambda: (prop:T) => P) : PropertyPathContexted {
return new PropertyPathContexted(obj, PropertyPath.get(lambda));
};
context: any
propertyPath: PropertyPath
constructor(context: any, propertyPath: PropertyPath) {
this.context = context
this.propertyPath = propertyPath
}
getValue = () => this.propertyPath.getValue(this.context)
setValue = ( value : any) => {this.propertyPath.setValue(this.context, value) }
}
And usage:
和用法:
var p = PropertyPathContexted.get(data, () => data.person.middleName)
var v = p.getValue()
p.setValue("lala")
I find the the latest quite convenient in two-way databinding in React:
我发现最新的 React 双向数据绑定非常方便:
var valueLink = function<T, P>( context: T, lambda: (prop:T) => P) {
var p = PropertyPathContexted.get(context, lambda);
return {
value: p.getValue(),
requestChange: (newValue) => {
p.setValue(newValue);
}
}
};
render() {
var data = getSomeData()
//...
return (
//...
<input name='person.surnames' placeholder='Surnames' valueLink={valueLink(data, () => data.person.surnames)}/>
//...
)
}