我有一个函数,该函数需要参数中的另一个函数。 我想返回由传入参数的函数的返回类型配置的通用接口。
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.appname.dev, PID: 25576
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.appname.dev/com.facebook.accountkit.ui.AccountKitActivity}: android.view.InflateException: Binary XML file line #26: Binary XML file line #26: Error inflating class TextView
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2831)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2906)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4778)
at android.app.ActivityThread.-wrap18(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1611)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:172)
at android.app.ActivityThread.main(ActivityThread.java:6637)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: android.view.InflateException: Binary XML file line #26: Binary XML file line #26: Error inflating class TextView
Caused by: android.view.InflateException: Binary XML file line #26: Error inflating class TextView
Caused by: java.lang.UnsupportedOperationException: Can't convert value at index 37 to dimension: type=0x1
at android.content.res.TypedArray.getDimensionPixelSize(TypedArray.java:730)
at android.view.View.<init>(View.java:4998)
at android.widget.TextView.<init>(TextView.java:824)
at android.widget.TextView.<init>(TextView.java:818)
at android.support.v7.widget.ab.<init>(AppCompatTextView.java:76)
at android.support.v7.widget.ab.<init>(AppCompatTextView.java:72)
at android.support.v7.app.AppCompatViewInflater.a(AppCompatViewInflater.java:176)
at android.support.v7.app.AppCompatViewInflater.a(AppCompatViewInflater.java:101)
at android.support.v7.app.j.b(AppCompatDelegateImplV9.java:1035)
at android.support.v7.app.j.onCreateView(AppCompatDelegateImplV9.java:1092)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:772)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at com.facebook.accountkit.ui.be$a.a(TitleFragmentFactory.java:87)
at com.facebook.accountkit.ui.ai.onCreateView(LoginFragment.java:43)
at com.facebook.accountkit.ui.be$a.onCreateView(TitleFragmentFactory.java:50)
at android.app.Fragment.performCreateView(Fragment.java:2611)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1276)
at android.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1549)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1611)
at android.app.FragmentManagerImpl.dispatchMoveToState(FragmentManager.java:3039)
at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:2991)
at android.app.FragmentController.dispatchActivityCreated(FragmentController.java:178)
at android.app.Activity.performCreateCommon(Activity.java:6969)
at android.app.Activity.performCreate(Activity.java:6977)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2784)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2906)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4778)
at android.app.ActivityThread.-wrap18(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1611)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:172)
at android.app.ActivityThread.main(ActivityThread.java:6637)
E/AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
然后,我想使getter函数成为可选函数,并为此使用默认值。当时发生了问题。
function doSomething <T>(values: Whatever[], getter: (whatever: Whatever) => T): T[] {
return values.map(value => getter(value));
}
所以现在我得到错误提示:
错误:(18,47)TS2322:类型'(val:Whatever)=>什么都不能分配给类型'(whatever:Whatever)=> T'。 无法将“无论”类型分配给“ T”类型。
您知道为什么我会收到该错误吗?
先谢谢您
(以下示例不是我的真实代码,但这对于描述我的问题更加清楚)
我正在使用打字稿2.7.2
答案 0 :(得分:4)
问题在于默认的getter函数的返回类型为Whatever
,但是doSomething
声明要求getter必须返回T
。 T
是泛型类型参数,可以是任何类型,不能保证Whatever
与T
兼容。 TypeScript编译器看不到提供默认值时不需要T
,并且返回的doSomething
类型为Whatever[]
。但是您可以使用doSomething
的这些重载声明来表达它:
function doSomething<T>(values: Whatever[], getter: (whatever: Whatever) => T): T[];
function doSomething(values: Whatever[]): Whatever[];
// the implementation must be compatible with both variants
function doSomething<T>(values: Whatever[], getter: (whatever: Whatever) => T | Whatever = val => val ): (T | Whatever)[] {
return values.map(value => getter(value));
}
更新以解决明确的问题:
我想避免返回“ Whatever | T”,因为每次我都会 调用此函数,我将必须检查响应类型(无论是 T)。
调用此函数时,仅考虑两个重载签名,当在doSomething()
的调用站点执行重载解析时,TypeScript不使用实现签名。实际上,实现返回类型可以简单地声明为any
,因为它是在重载documentation examples中完成的-它仅用于对实现进行类型检查,并且实现通常很明显,因此更严格的类型可以在那里没有提供太多好处。
我想编写代码以获取getter函数的返回类型并用作T。
如果在调用doSomething
时省略了通用参数,则编译器将从T
返回类型中推断getter
。我认为以下示例可以满足您的要求:
interface Whatever { w: string };
function doSomething<T>(values: Whatever[], getter: (whatever: Whatever) => T): T[];
function doSomething(values: Whatever[]): Whatever[];
function doSomething<T>(values: Whatever[], getter: (whatever: Whatever) => T | Whatever = val => val ): (T | Whatever)[] {
return values.map(value => getter(value));
}
function example() {
const getter1 = (whatever: Whatever) => whatever.w; // returns string
const getter2 = (whatever: Whatever) => whatever.w.length; // returns number
const values: Whatever[] = [];
const r0 = doSomething(values); // const r1: Whatever[]
const r1 = doSomething(values, getter1); // const r1: string[]
const r2 = doSomething(values, getter2); // const r2: number[]
}
答案 1 :(得分:0)
如您所希望的那样,在没有给出getter的情况下采取默认行为,我认为完全可以尝试使用默认的getter进行强制转换:val => val as T
function doSomething <T>(values: Whatever[], getter: (whatever: Whatever) => T = val => val as T): T[] {
return values.map(getter);
}
并且Typescript仅是“编译时”类型安全的语法糖,这意味着:“尝试按原样获取值,而无需任何映射”。因此,如果您仔细考虑一下,如果没有给出getter,则意味着它实际上不会更改数组的值。根据使用情况,您也可以这样做
function doSomething <T>(values: Whatever[], getter?: (whatever: Whatever) => T): T[] {
if (getter === undefined) { return values as T[]; }
return values.map(value => getter(value));
}
并跳过map(),该操作除了复制数组外什么都不做,如果那是您想要的那种情况:
return [...values] as T[]
代替返回副本。