为子类工厂键入注释

时间:2017-10-26 15:01:24

标签: javascript reactjs typescript

我最近开始将我公司的一个项目的代码库迁移到TypeScript,并且我很难对这段代码进行类型注释:

RecyclerViewAdapter

我尝试用TypeScript描述:

  • factory仅接受从React.Component类继承的类。
  • factory返回继承自React.Component类的类。

我尝试了什么:

@Override
public void onClick(View v) {
    Intent i = ProductPageActivity.newIntent(v.getContext(),mProduct.getId());
    v.getContext().startActivity(i);
}
}
public class ProductFragment extends Fragment {
    private static final String TAG = "ProductFragment";
    private static final String ARGUMENT_PROD_ID = "prod_id";
    private TextView mTitle,mDesc,mImgUrl,mPrice;
    private List<Product> mProducts;
    private Product product;



    public static Fragment newInstance(UUID productID) {
        Bundle args = new Bundle();
        args.putSerializable(ARGUMENT_PROD_ID,productID);
        ProductFragment frag = new ProductFragment();
        frag.setArguments(args);
        return frag;
    }

    public ProductFragment() {}

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(getArguments() != null) {
            UUID id = (UUID) getArguments().getSerializable(ARGUMENT_PROD_ID);
            product = ProductHolder.get(getContext()).getProduct(id);
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.product_fragment,container,false);
        setWidgets(v);
        setDataOnText();
        return v;
    }

    private void setDataOnText(){
        mTitle.setText(product.getTitle());
        mDesc.setText(product.getDesc());
        mPrice.setText(product.getPrice());
    }

    private void setWidgets(View v) {
        mTitle = (TextView) v.findViewById(R.id.title);
        mDesc = (TextView) v.findViewById(R.id.desc);
        mPrice = (TextView) v.findViewById(R.id.price);
    }
}

public class ProductPageActivity extends AppCompatActivity {
    private static final String PRODUCT_ID = "com.example.cmd.testproject.Activitys.ProductPageActivity.product_id";
    private UUID productId;

    private ViewPager mPager;
    private List<Product> mProducts;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.product_page_activity);

        productId = (UUID) getIntent().getSerializableExtra(PRODUCT_ID);

        mPager = (ViewPager) findViewById(R.id.viewPager);

        mProducts = ProductHolder.get(this).getProducts();
        FragmentManager fragmentManager = getSupportFragmentManager();
        mPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {

            @Override
            public Fragment getItem(int position) {
                Product pr = mProducts.get(position);
                return ProductFragment.newInstance(pr.getId());
            }

            @Override
            public int getCount() {
                return mProducts.size();
            }
        });

        for (int i = 0; i < mProducts.size(); i++) {
            if (mProducts.get(i).getId().equals(productId)) {
                mPager.setCurrentItem(i);
                break;
            }
        }
    }

    public static Intent newIntent(Context packageContext, UUID productID) {
        Intent intent = new Intent(packageContext, ProductPageActivity.class);
        intent.putExtra(PRODUCT_ID, productID);
        return intent;
    }
}

public class ProductHolder {
    private static final String TAG = "ProductHolder";
    private static ProductHolder sProductHolder;
    private List<Product> mProducts;

    public static ProductHolder get(Context ctx) {
        if(sProductHolder == null) {
            sProductHolder = new ProductHolder(ctx);
        }
        return sProductHolder;
    }

    private ProductHolder(Context ctx) {
            mProducts = new ArrayList<>();
            for (int i = 0; i < 4; i++) {
                Product product = new Product("Product = " + i, "Desc = "
                        + i, "ImgUrl = " + i, "Price = " + i + 2.2);
                mProducts.add(product);
            }
    }

    public Product getProduct(UUID prodId) {
        for (Product pr:mProducts) {
            if(pr.getId().equals(prodId));
            return pr;
        }
        return null;
    }

    public List<Product> getProducts() {
        return mProducts;
    }
}

这在类型检查方面非常糟糕。

我正在使用:

  • TypeScript 2.5.2
  • Visual Studio Code 1.16.1
  • @ types / react 16.0.14

2 个答案:

答案 0 :(得分:1)

似乎我设法让它与它一起工作:

type RCConstructor<P, S> = new(...args: any[]) => React.Component<P, S>;

function factory<T extends RCConstructor<{}, {}>> ( Base: T ) {
  return class Extended extends Base {
    /* Extended implementation */
  };
}

export const Extended = factory( React.Component );
export const PureExtended = factory( React.PureComponent );

解决方案来自https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html。从文档中可以看出这里发生了什么。现在真正的问题是“为什么https://www.typescriptlang.org/docs/handbook/mixins.html没有涵盖这个?”。

答案 1 :(得分:0)

如您在答案中链接的文章中所示,使mixin工作所需的是Constructor类型。 (可选)您可以通过向Constructor提供特定类型来约束可以扩展的类。

type Constructor<T> = new(...args: any[]) => T;

function factory<T extends Constructor<React.Component>> ( Base: T ) {
  return class Extended extends Base {
    /* Extended implementation */
  };
}

export const Extended = factory( React.Component );
export const PureExtended = factory( React.PureComponent );