Typescript接口属性为string

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Typescript接口属性为string相关的知识,希望对你有一定的参考价值。

目的

我有一个接口TypeScript:

interface IInterface
    id: number;
    name: string;

我有一些方法可以输入属性的名称(字符串)。

例如:

var methodX = ( property: string, object: any ) => 
    // use object[property]
;

我的问题是,当我调用methodX时,我必须在字符串中写入属性名称。

例如:对象实现接口的methodX("name", objectX);

但这很糟糕:如果我重命名一个属性(假设我想将name重命名为lastname),我将不得不手动更新我的所有代码。

我不希望这种依赖。

由于typescript接口没有JS实现,我不知道我怎么不能使用字符串。

我希望有类似的东西:methodX(IInterface.name.propertytoString(), objectX);

我是JS的新手,你看到另一种选择吗?

(可选)更多细节:为什么我需要将属性作为参数传递,为什么我不使用泛型方法?

我使用链接数据的方法:

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;
        
    
;

但TA和TB可以有很多不同的ID。所以我不知道如何使它更通用。

答案

basarat答案是一个好主意,但它不适用于接口。

你不能写methodX(interfacePropertyToString(()=>interfaceX.porpertyname), objectX)因为interfaceX不是一个对象。

接口是抽象,它们仅用于TypeScript,它们在javascript中不存在。

但是由于他的回答,我找到了解决方案:在方法中使用参数。

最后我们有:

    interfacePropertyToString = ( property: (object: any) => void ) => 
        var chaine = property.toString();
        var arr = chaine.match( /[\s\S]*[\s\S]*\.([^\.; ]*)[ ;\n]*/ );
        return arr[1];
    ;

我们必须使用[\s\S]才能在多线上匹配,因为Typescript将(object: Interface) => object.code;转换为多线函数。

现在您可以根据需要使用它:

        interfacePropertyToString(( o: Interface ) =>  o.interfaceProperty);
        interfacePropertyToString( function ( o: Interface  )  o.interfaceProperty);
另一答案

您可以编写一个函数来解析函数体,以查找名称,例如:

methodX(getName(()=>something.name), objectX)

其中getName将在函数体上执行toString以获取"function()return something.name"形式的字符串,然后解析它以获得"name"

注意:然而,根据您如何缩小它,这种趋势会有所突破。

另一答案

一些相关的问题 - 如何获取/设置属性路径的值。我写了两个课:

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)
    


用法示例:

var p = PropertyPath.get((data:Data) => data.person.middleName)
var v = p.getValue(data)
p.setValue(data, newValue)

一些糖:

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) 


用法:

var p = PropertyPathContexted.get(data, () => data.person.middleName)
var v = p.getValue()
p.setValue("lala")

我在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)/>
       //...
   )

另一答案

我稍微更改了basarat代码,因此我们可以将它用作通用代码:

const P = <T>( property: (object: T) => void ) => 
    const chaine = property.toString();
    const arr = chaine.match( /[\s\S]*[\s\S]*\.([^\.; ]*)[ ;\n]*/ );
    return arr[1];
;

示例用法:

console.log(P<MyInterface>(p => p.propertyName));

以上是关于Typescript接口属性为string的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据组表示为通用 Typescript 接口

TypeScript——接口

带有属性的函数的 TypeScript 接口

在 TypeScript 接口中描述属性对象

从0开始的TypeScriptの四:接口Interfaces · 上

从0开始的TypeScriptの四:接口Interfaces · 上